python - websites - mastering django core
Slugification de cadenas en Python (9)
El problema es con la línea de normalización ascii:
slug = unicodedata.normalize(''NFKD'', s)
Se llama normalización unicode que no descompone muchos caracteres en ascii. Por ejemplo, eliminaría caracteres no ascii de las siguientes cadenas:
Mørdag -> mrdag
Æther -> ther
Una mejor forma de hacerlo es usar el módulo unidecode que intenta transliterar cadenas a ascii. Entonces si reemplaza la línea anterior con:
import unidecode
slug = unidecode.unidecode(s)
Obtendrá mejores resultados para las cadenas anteriores y para muchos caracteres griegos y rusos también:
Mørdag -> mordag
Æther -> aether
Estoy en busca de la mejor manera de "slugificar" la secuencia de lo que es "slug" , y mi solución actual se basa en esta receta
Lo he cambiado un poco para:
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)
¿Alguien ve algún problema con este código? Está funcionando bien, pero tal vez me falta algo o ¿sabes una mejor manera?
Funciona bien en Django , así que no veo por qué no sería una buena función slugify de propósito general.
¿Tienes algún problema con eso?
Hay un paquete de Python llamado awesome-slugify :
pip install awesome-slugify
Funciona así:
from slugify import slugify
slugify(''one kožušček'') # one-kozuscek
Hay un paquete de python llamado python-slugify
, que hace un buen trabajo de slugifying:
pip install python-slugify
Funciona así:
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")
Ver más ejemplos
Este paquete hace un poco más de lo que publicaste (echa un vistazo a la fuente, es solo un archivo). El proyecto aún está activo (se actualizó 2 días antes de que respondiera originalmente, más de cuatro años después (se verificó por última vez el 2017-04-26), todavía se actualiza).
cuidado : hay un segundo paquete, llamado slugify
. Si tiene ambos, es posible que tenga un problema, ya que tienen el mismo nombre para importar. El que acabo de slugify
no hizo todo lo que comprobé rápidamente: "Ich heiße"
convirtió en "ich-heie"
(debería ser "ich-heisse"
), así que asegúrese de elegir el correcto, cuando use pip
o easy_install
.
Instalar el formulario unidecode desde aquí para soporte unicode
pip install 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-world
Puede considerar cambiar la última línea a
slug=re.sub(r''--+'',r''-'',slug)
ya que el patrón [-]+
no es diferente de -+
, y realmente no le importa emparejar solo un guión, solo dos o más.
Pero, por supuesto, esto es bastante menor.
Un par de opciones en GitHub:
- https://github.com/dimka665/awesome-slugify
- https://github.com/un33k/python-slugify
- https://github.com/mozilla/unicode-slugify
Cada uno admite parámetros ligeramente diferentes para su API, por lo que deberá consultar para descubrir qué prefiere.
En particular, preste atención a las diferentes opciones que ofrecen para tratar con caracteres que no son ASCII. Pydanny escribió una muy útil publicación de blog que ilustra algunas de las diferencias de manejo unicode en estas bibliotecas de slugify: http://www.pydanny.com/awesome-slugify-human-readable-url-slugs-from-any-string.html Esta publicación de blog está un poco desactualizada porque el unicode-slugify
ya no es específico de Django.
También tenga en cuenta que actualmente awesome-slugify
es GPLv3, aunque hay un problema abierto en el que el autor dice que preferiría publicarlo como MIT / BSD, simplemente no está seguro de la legalidad: https://github.com/dimka665/awesome-slugify / issues / 24
Unidecode es bueno; sin embargo, tenga cuidado: unidecode es GPL. Si esta licencia no cabe, utiliza esta
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)
Esta es la función slugify presente en django.utils.text Esto debería ser suficiente.