Chuỗi sên bằng Python


97

Tôi đang tìm kiếm cách tốt nhất để "slugify" chuỗi "slug" là gì và giải pháp hiện tại của tôi dựa trên công thức này

Tôi đã thay đổi nó một chút thành:

s = 'String to slugify'

slug = unicodedata.normalize('NFKD', s)
slug = slug.encode('ascii', 'ignore').lower()
slug = re.sub(r'[^a-z0-9]+', '-', slug).strip('-')
slug = re.sub(r'[-]+', '-', slug)

Có ai thấy bất kỳ vấn đề nào với mã này không? Nó đang hoạt động tốt, nhưng có thể tôi đang thiếu một cái gì đó hoặc bạn biết một cách tốt hơn?


bạn đang làm việc với rất nhiều unicode? nếu vậy, re.sub cuối cùng có thể tốt hơn nếu bạn quấn unicode () xung quanh nó, Đây là những gì django làm. Ngoài ra, [^ a-z0-9] + có thể được rút ngắn để sử dụng \ w. xem django.template.defaultfilters, nó gần giống với của bạn, nhưng tinh tế hơn một chút.
Mike Ramirez

Các ký tự unicode có được phép trong URL không? Ngoài ra, tôi đã thay đổi \ w thành a-z0-9 vì \ w bao gồm ký tự _ và các chữ cái viết hoa. Các chữ cái được đặt thành chữ thường trước, vì vậy sẽ không có chữ hoa nào phù hợp.
Zygimantas

'_' là hợp lệ (nhưng sự lựa chọn của bạn, bạn đã hỏi), unicode là các ký tự được mã hóa theo phần trăm.
Mike Ramirez

Cảm ơn Mike. Vâng, tôi đã hỏi một câu hỏi sai. Có bất kỳ lý do gì để mã hóa nó trở lại chuỗi unicode, nếu chúng tôi đã thay thế tất cả các ký tự ngoại trừ "az", "0-9" và "-"?
Zygimantas

Đối với django, tôi tin rằng điều quan trọng đối với họ là phải có tất cả các chuỗi dưới dạng đối tượng unicode để tương thích. Đó là sự lựa chọn của bạn nếu bạn muốn điều này.
Mike Ramirez

Câu trả lời:


146

Có một gói python được đặt tên python-slugify, thực hiện khá tốt công việc xử lý nước thải:

pip install python-slugify

Hoạt động như thế này:

from slugify import slugify

txt = "This is a test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = "This -- is a ## test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = 'C\'est déjà l\'été.'
r = slugify(txt)
self.assertEquals(r, "cest-deja-lete")

txt = 'Nín hǎo. Wǒ shì zhōng guó rén'
r = slugify(txt)
self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")

txt = 'Компьютер'
r = slugify(txt)
self.assertEquals(r, "kompiuter")

txt = 'jaja---lol-méméméoo--a'
r = slugify(txt)
self.assertEquals(r, "jaja-lol-mememeoo-a")

Xem thêm các ví dụ

Gói này làm được nhiều hơn một chút so với những gì bạn đã đăng (hãy xem nguồn, nó chỉ là một tệp). Dự án vẫn đang hoạt động (được cập nhật 2 ngày trước khi tôi trả lời ban đầu, hơn bảy năm sau (kiểm tra lần cuối 2020-06-30), nó vẫn được cập nhật).

cẩn thận : Có một gói thứ hai xung quanh, được đặt tên slugify. Nếu bạn có cả hai, bạn có thể gặp sự cố, vì chúng có cùng tên để nhập. Cái vừa được đặt tên slugifykhông làm được tất cả những gì tôi đã kiểm tra nhanh: "Ich heiße"trở thành "ich-heie"(nên là "ich-heisse"), vì vậy hãy đảm bảo chọn đúng, khi sử dụng piphoặc easy_install.


6
python-slugifyđược cấp phép theo MIT, nhưng nó sử dụng Unidecodeđược cấp phép theo GPL, vì vậy nó có thể không phù hợp với một số dự án.
Rotareti

@Rotareti Bạn có thể vui lòng giải thích cho tôi lý do tại sao nó không thể phù hợp với tất cả các dự án không? Chúng tôi không thể sử dụng bất kỳ thứ gì theo giấy phép MIT hoặc GPL và đưa chúng vào phần mềm thương mại? Tôi nghĩ hạn chế duy nhất là đặt giấy phép bên cạnh các mã chúng tôi phát triển. Tôi có lầm không?
Ghassem Tofighi, 14/07/19

1
@GhassemTofighi Tóm lại: Bạn có thể sử dụng nó trong phần mềm thương mại của mình, nhưng nếu bạn sử dụng nó, bạn cũng phải mở mã nguồn của mình. Dù sao IANAL và đây không phải là lời khuyên pháp lý.
Rotareti

@GhassemTofighi có thể có một cái nhìn tại softwareengineering.stackexchange.com/q/47032/71504 về chủ đề đó
kratenko

1
@Rotareti python-slugifyhiện mặc định text-unidecodelà Giấy phép nghệ thuật thay vì được cấp phép GPL Unidecode, giải quyết mối lo ngại về cấp phép của bạn. github.com/un33k/python-slugify/commit/…
Emilien

31

Cài đặt biểu mẫu unidecode từ đây để được hỗ trợ unicode

pip cài đặt mã unidecode

# -*- coding: utf-8 -*-
import re
import unidecode

def slugify(text):
    text = unidecode.unidecode(text).lower()
    return re.sub(r'[\W_]+', '-', text)

text = u"My custom хелло ворлд"
print slugify(text)

>>> my-custom-khello-vorld


1
hi, một mình cắn kỳ lạ nhưng nó cung cấp cho cho res của tôi như thế "my-custom-ndud-d-d3-4-d2d3-4nd-d-"
Derevo

1
@derevo đã xảy ra khi bạn không gửi chuỗi unicode. Thay thế slugify("My custom хелло ворлд")bằng slugify(u"My custom хелло ворлд"), và nó sẽ hoạt động.
kratenko

9
Tôi sẽ đề nghị không sử dụng các tên biến như str. Điều này ẩn strloại nội trang .
crodjer

2
unidecode là GPL, có thể không phù hợp với một số người.
Jorge Leitao

Điều gì về sự sung túc hoặc làm giảm chất lượng.
Ryan Chou

11

Có gói python có tên awesome-slugify :

pip install awesome-slugify

Hoạt động như thế này:

from slugify import slugify

slugify('one kožušček')  # one-kozuscek

trang github tuyệt vời-slugify


2
Gói đẹp! Nhưng hãy cẩn thận, nó được cấp phép theo GPL.
Rotareti

1
Lưu ý: điều này sẽ không tự động .lower () url của bạn. Bạn sẽ cần phải chạy slugify(text).lower()nếu bạn muốn điều đó.
Kalob Taulien

7

Nó hoạt động tốt trong Django , vì vậy tôi không hiểu tại sao nó không phải là một chức năng slugify mục đích chung tốt.

Bạn có gặp vấn đề gì với nó không?


Có thể, đó là đối với một số trường hợp, đó là một liều lành mạnh của hoang tưởng :-)
nemesisfixx

Mã đã chuyển đến đây .
raylu,

13
Dành cho những kẻ lười biếng:from django.utils.text import slugify
Spartacus

6

Vấn đề là với dòng chuẩn hóa ascii:

slug = unicodedata.normalize('NFKD', s)

Nó được gọi là chuẩn hóa unicode không phân hủy nhiều ký tự thành ascii. Ví dụ: nó sẽ tách các ký tự không phải ascii khỏi các chuỗi sau:

Mørdag -> mrdag
Æther -> ther

Một cách tốt hơn để làm điều đó là sử dụng mô-đun unidecode cố gắng chuyển các chuỗi thành ascii. Vì vậy, nếu bạn thay thế dòng trên bằng:

import unidecode
slug = unidecode.unidecode(s)

Bạn sẽ nhận được kết quả tốt hơn cho các chuỗi trên và cho nhiều ký tự Hy Lạp và Nga:

Mørdag -> mordag
Æther -> aether

6
def slugify(value):
    """
    Converts to lowercase, removes non-word characters (alphanumerics and
    underscores) and converts spaces to hyphens. Also strips leading and
    trailing whitespace.
    """
    value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
    value = re.sub('[^\w\s-]', '', value).strip().lower()
    return mark_safe(re.sub('[-\s]+', '-', value))
slugify = allow_lazy(slugify, six.text_type)

Đây là hàm slugify có trong django.utils.text. Điều này sẽ đáp ứng đủ yêu cầu của bạn.


3

Unidecode là tốt; tuy nhiên, hãy cẩn thận: unidecode là GPL. Nếu giấy phép này không phù hợp thì hãy sử dụng giấy phép này


2

Một số tùy chọn trên GitHub:

  1. https://github.com/dimka665/awesome-slugify
  2. https://github.com/un33k/python-slugify
  3. https://github.com/mozilla/unicode-slugify

Mỗi loại hỗ trợ các thông số hơi khác nhau cho API của nó, vì vậy bạn sẽ cần xem qua để tìm ra những gì bạn thích.

Đặc biệt, hãy chú ý đến các tùy chọn khác nhau mà họ cung cấp để xử lý các ký tự không phải ASCII. Pydanny đã viết một bài đăng blog rất hữu ích minh họa một số khác biệt về xử lý unicode trong các thư viện slugify'ing này: http://www.pydanny.com/awesome-slugify-human-readable-url-slugs-from-any-string.html Bài đăng trên blog này hơi lỗi thời vì Mozilla unicode-slugifykhông còn dành riêng cho Django nữa.

Cũng lưu ý rằng hiện tại awesome-slugifylà GPLv3, mặc dù có một vấn đề mở mà tác giả nói rằng họ muốn phát hành dưới dạng MIT / BSD, chỉ là không chắc chắn về tính hợp pháp: https://github.com/dimka665/awesome-slugify/issues/ 24


1

Bạn có thể cân nhắc thay đổi dòng cuối cùng thành

slug=re.sub(r'--+',r'-',slug)

vì mẫu [-]+không khác gì -+và bạn không thực sự quan tâm đến việc chỉ khớp một dấu gạch nối, chỉ hai hoặc nhiều hơn.

Nhưng, tất nhiên, điều này là khá nhỏ.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.