Python'da dize slugification


97

"Sümüklü böcek" dizesini "sümüklü böcek" haline getirmenin en iyi yolunu arıyorum ve mevcut çözümüm bu tarife dayanıyor

Bunu biraz değiştirdim:

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)

Bu kodla ilgili herhangi bir sorun gören var mı? İyi çalışıyor, ama belki bir şeyi kaçırıyorum veya daha iyi bir yol biliyorsunuz?


Unicode ile çok mu çalışıyorsun? eğer öyleyse, etrafına unicode () sararsanız son re.sub daha iyi olabilir, django'nun yaptığı budur. Ayrıca [^ a-z0-9] +, \ w kullanmak için kısaltılabilir. django.template.defaultfilters'a bakın, sizinkine yakın, ancak biraz daha rafine.
Mike Ramirez

URL'de unicode karakterlere izin verilir mi? Ayrıca, \ w'yi a-z0-9 olarak değiştirdim çünkü \ w, _ karakterini ve büyük harfleri içeriyor. Harfler önceden küçük harfe ayarlanmıştır, bu nedenle eşleşecek büyük harfler olmayacaktır.
Zygimantas

'_' geçerlidir (ancak seçiminiz, sordunuz), unicode yüzde olarak kodlanmış karakterlerdir.
Mike Ramirez

Teşekkürler Mike. Yanlış soru sordum. "Az", "0-9" ve "-" dışındaki tüm karakterleri zaten değiştirdiysek, onu tekrar unicode dizgesine kodlamak için herhangi bir neden var mı?
Zygimantas

Django için, uyumluluk açısından tüm dizeleri unicode nesneler olarak almanın onlar için önemli olduğuna inanıyorum. Bunu istiyorsan seçim senin.
Mike Ramirez

Yanıtlar:


146

python-slugifyAdında bir python paketi var ve bu oldukça iyi bir slugifying işi yapıyor:

pip install python-slugify

Şu şekilde çalışır:

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")

Daha fazla örnek görün

Bu paket, gönderdiklerinizden biraz daha fazlasını yapar (kaynağa bir bakın, bu sadece bir dosya). Proje hala aktif (ilk yanıtlamamdan 2 gün önce, yedi yıl sonra (en son 2020-06-30 kontrol edildi) güncellendi, hala güncelleniyor).

dikkatli : Etrafta adında ikinci bir paket var slugify. İkisine de sahipseniz, içe aktarma için aynı ada sahip oldukları için bir sorunla karşılaşabilirsiniz. Adı geçen kişi slugifyhızlı kontrol ettiğim her şeyi yapmadı: "Ich heiße"oldu "ich-heie"(olmalı "ich-heisse"), bu yüzden pipveya kullanırken doğru olanı seçtiğinizden emin olun easy_install.


6
python-slugifyMIT altında lisanslanmıştır, ancak UnidecodeGPL altında lisanslanmış olanı kullanır , bu nedenle bazı projeler için uygun olmayabilir.
Rotareti

@Rotareti Neden tüm projelere uymadığını bana açıklar mısınız? MIT veya GPL lisansı altında herhangi bir şey kullanıp bunları ticari yazılıma dahil edemez miyiz? Sanırım tek kısıtlama lisansı geliştirdiğimiz kodların yanında koymak. Yanlış mıyım?
Ghassem Tofighi

1
@GhassemTofighi Kısaca: Ticari yazılımlarınızda kullanabilirsiniz, ancak kullanırsanız kodunuzu da açık kaynak kodlu hale getirmelisiniz. Her neyse IANAL ve bu yasal bir tavsiye değil.
Rotareti

@GhassemTofighi belki bakmak softwareengineering.stackexchange.com/q/47032/71504 o konuda
kratenko

1
@Rotareti python-slugifyartık text-unidecodeGPL lisanslı yerine varsayılan olarak Artistik Lisansı ile Unidecodelisanslama sorununuzu gideriyor . github.com/un33k/python-slugify/commit/…
Emilien

31

Unicode desteği için unidecode formunu buradan yükleyin

pip yüklemek 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)

>>> benim-özel-khello-vorld


1
merhaba, biraz tuhaf ama "özel-ndud-d-d3-4-d2d3-4nd-d-" gibi
resmime veriyor

1
@derevo, unicode dizeleri göndermediğinizde olur. Değiştir slugify("My custom хелло ворлд")ile slugify(u"My custom хелло ворлд"), ve çalışması gerekir.
kratenko

9
Gibi değişken isimlerini kullanmamanızı öneririm str. Bu yerleşik strtürü gizler .
crodjer

2
unidecode, bazıları için uygun olmayan GPL'dir.
Jorge Leitao

Yeniden fişe çekme veya fişten çıkarma işlemine ne dersiniz?
Ryan Chou

11

Awesome-slugify adında bir python paketi var :

pip install awesome-slugify

Şu şekilde çalışır:

from slugify import slugify

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

harika slugify github sayfası


2
Güzel paket! Ancak dikkatli olun, GPL lisansına sahiptir.
Rotareti

1
Dikkat: Bu otomatik olarak URL'lerinizi düşürmez (). Bunu slugify(text).lower()istiyorsan koşman gerekecek .
Kalob Taulien

7

Bu iyi çalışır Django iyi bir genel amaçlı slugify fonksiyonu olmaz neden görmüyorum bu yüzden.

Bununla ilgili herhangi bir sorunun var mı?


Bazı durumlarda sağlıklı bir paranoya dozu olması mümkündür :-)
nemesisfixx

Kod buraya taşındı .
raylu

13
Tembeller için:from django.utils.text import slugify
Spartacus

6

Sorun, ascii normalleştirme hattında:

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

Çok sayıda karakteri ascii'ye ayırmayan unicode normalleştirme denir . Örneğin, ascii olmayan karakterleri aşağıdaki dizelerden çıkarır:

Mørdag -> mrdag
Æther -> ther

Bunu yapmanın daha iyi bir yolu, dizeleri ascii'ye çevirmeye çalışan unidecode modülünü kullanmaktır . Dolayısıyla, yukarıdaki satırı şu şekilde değiştirirseniz:

import unidecode
slug = unidecode.unidecode(s)

Yukarıdaki dizeler ve birçok Yunanca ve Rusça karakter için de daha iyi sonuçlar alırsınız:

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)

Bu, django.utils.text içinde bulunan slugify işlevidir.



2

GitHub'da birkaç seçenek:

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

Her biri, API'si için biraz farklı parametreleri destekler, bu nedenle neyi tercih ettiğinizi bulmak için incelemeniz gerekir.

Özellikle, ASCII olmayan karakterlerle uğraşmak için sağladıkları farklı seçeneklere dikkat edin. Pydanny, bu slugify'ing kitaplıklarındaki bazı unicode işleme farklılıklarını gösteren çok yararlı bir blog yazısı yazdı: http://www.pydanny.com/awesome-slugify-human-readable-url-slugs-from-any-string.html Mozilla'nınki unicode-slugifyartık Django'ya özgü olmadığı için bu blog yazısı biraz eski .

Ayrıca şu anda awesome-slugifyGPLv3 olduğunu unutmayın , ancak yazarın yasallıktan emin olmadan MIT / BSD olarak yayınlamayı tercih edeceğini söylediği bir açık sorun var: https://github.com/dimka665/awesome-slugify/issues/ 24


1

Son satırı şu şekilde değiştirmeyi düşünebilirsiniz:

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

desen [-]+farklı olmadığı -+ve yalnızca bir kısa çizgiyi eşleştirmeyi gerçekten önemsemediğiniz için, yalnızca iki veya daha fazla.

Ama elbette bu oldukça önemsiz.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.