utf8 - Normalización de texto Unicode a nombres de archivo, etc. en Python
manejo de archivos binarios en python (5)
¿Existe alguna solución estándar para normalizar el texto internacional de Unicode a las ID y los nombres de archivo seguros en Python?
Por ejemplo, gire My International Text: åäö
a my-international-text-aao
plone.i18n hace realmente un buen trabajo, pero desafortunadamente depende de zope.security
y zope.publisher
y algunos otros paquetes que lo hacen frágil dependencia.
La manera de resolver este problema es tomar una decisión sobre qué caracteres se permiten (los diferentes sistemas tienen diferentes reglas para identificadores válidos).
Una vez que decida qué caracteres están permitidos, escriba un predicado permitido () y una subclase dict para usar con str.translate :
def makesafe(text, allowed, substitute=None):
'''''' Remove unallowed characters from text.
If *substitute* is defined, then replace
the character with the given substitute.
''''''
class D(dict):
def __getitem__(self, key):
return key if allowed(chr(key)) else substitute
return text.translate(D())
Esta función es muy flexible. Le permite especificar fácilmente las reglas para decidir qué texto se conserva y qué texto se reemplaza o elimina.
Aquí hay un ejemplo simple que usa la regla, "solo se permiten los caracteres que están en la categoría L de Unicode":
import unicodedata
def allowed(character):
return unicodedata.category(character).startswith(''L'')
print(makesafe(''the*ides&of*march'', allowed, ''_''))
print(makesafe(''the*ides&of*march'', allowed))
Ese código produce una salida segura de la siguiente manera:
the_ides_of_march
theidesofmarch
Lanzaré mi propia solución (parcial) aquí también:
import unicodedata
def deaccent(some_unicode_string):
return u''''.join(c for c in unicodedata.normalize(''NFD'', some_unicode_string)
if unicodedata.category(c) != ''Mn'')
Esto no hace todo lo que quiere, pero le brinda algunos trucos unicode.normalise(''NFD'', some_unicode_string)
envueltos en un método conveniente: unicode.normalise(''NFD'', some_unicode_string)
realiza una descomposición de caracteres Unicode, por ejemplo, rompe ''ä'' en dos puntos de código Unicode. U+03B3
y U+0308
.
El otro método, unicodedata.category(char)
, devuelve la categoría de caracteres enicode para ese char
particular. La categoría Mn
contiene todos los acentos de combinación, por lo tanto, deaccent
elimina todos los acentos de las palabras.
Pero tenga en cuenta que esto es solo una solución parcial, se deshace de los acentos. Todavía necesita algún tipo de lista blanca de caracteres que desee permitir después de esto.
Lo que quieres hacer también se conoce como "slugify" una cadena. Aquí hay una posible solución:
import re
from unicodedata import normalize
_punct_re = re.compile(r''[/t !"#$%&/'()*/-/<=>?@/[///]^_`{|},.:]+'')
def slugify(text, delim=u''-''):
"""Generates an slightly worse ASCII-only slug."""
result = []
for word in _punct_re.split(text.lower()):
word = normalize(''NFKD'', word).encode(''ascii'', ''ignore'')
if word:
result.append(word)
return unicode(delim.join(result))
Uso:
>>> slugify(u''My International Text: åäö'')
u''my-international-text-aao''
También puedes cambiar el delimitador:
>>> slugify(u''My International Text: åäö'', delim=''_'')
u''my_international_text_aao''
Fuente: Generating Slugs
Para Python 3: pastebin.com/ft7Yb3KS (gracias @MrPoxipol ).
Lo siguiente eliminará los acentos de cualquier carácter que Unicode pueda descomponer para combinar pares, descartar cualquier carácter extraño que no pueda, y destruir espacios en blanco:
# encoding: utf-8
from unicodedata import normalize
import re
original = u''ľ š č ť ž ý á í é''
decomposed = normalize("NFKD", original)
no_accent = ''''.join(c for c in decomposed if ord(c)<0x7f)
no_spaces = re.sub(r''/s'', ''_'', no_accent)
print no_spaces
# output: l_s_c_t_z_y_a_i_e
No intenta deshacerse de los caracteres no permitidos en los sistemas de archivos, pero puedes robar DANGEROUS_CHARS_REGEX
del archivo que vinculaste para eso.
Yo iria con
https://pypi.python.org/pypi?%3Aaction=search&term=slug
Es difícil encontrar un escenario donde uno de estos no se ajuste a sus necesidades.