Нормализация текста Unicode для имен файлов и т.д. В Python
Есть ли автономные решения для нормализации международного текста в Unicode для надежных идентификаторов и имен файлов в Python?
например. поверните My International Text: åäö
в my-international-text-aao
plone.i18n действительно хорошо работает, но, к сожалению, это зависит от zope.security
и zope.publisher
и некоторых других пакетов, что делает его хрупкой зависимостью.
Некоторые операции, которые применяются plone.i18n
Ответы
Ответ 1
То, что вы хотите сделать, также известно как "slugify" строка. Здесь возможно решение:
import re
from unicodedata import normalize
_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>[email protected]\[\\\]^_`{|},.:]+')
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))
Использование:
>>> slugify(u'My International Text: åäö')
u'my-international-text-aao'
Вы также можете изменить метрику:
>>> slugify(u'My International Text: åäö', delim='_')
u'my_international_text_aao'
Источник: Генерация слизней
Для Python 3: pastebin.com/ft7Yb3KS (спасибо @MrPoxipol).
Ответ 2
Способом решения этой проблемы является принятие решения о том, какие символы разрешены (разные системы имеют разные правила для действительных идентификаторов.
После того, как вы решите, какие символы разрешены, напишите допустимый() предикат и подклассом dict для использования с 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())
Эта функция очень гибкая. Это позволяет вам легко определять правила для определения того, какой текст сохранен и какой текст либо заменен, либо удален.
Вот простой пример использования правила: "разрешить только символы, которые находятся в категории Юникод L":
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))
Этот код производит безопасный вывод следующим образом:
the_ides_of_march
theidesofmarch
Ответ 3
Ниже будут удалены акценты из любых символов, которые Unicode может разложить на объединение пар, отбросить любые странные символы, которые он не может, и пробелы в ядерном пространстве:
# 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
Он не пытается избавиться от символов, запрещенных файловыми системами, но вы можете украсть DANGEROUS_CHARS_REGEX
из файла, который вы связали для этого.
Ответ 4
Я тоже брошу свое (частичное) решение:
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')
Это не делает все, что вы хотите, но дает несколько приятных трюков, завернутых в удобном методе: unicode.normalise('NFD', some_unicode_string)
выполняет разложение символов в Юникоде, например, разбивает 'ä' на два кодовых пункта unicode U+03B3
и U+0308
.
Другой метод unicodedata.category(char)
возвращает категорию символов enicode для этого конкретного char
. Категория Mn
содержит все сочетания акцентов, поэтому deaccent
удаляет все акценты из слов.
Но обратите внимание, что это всего лишь частичное решение, оно избавляется от акцентов. Вам все равно нужен какой-то белый список символов, который вы хотите разрешить после этого.
Ответ 5
Я бы пошел с
https://pypi.python.org/pypi?%3Aaction=search&term=slug
Сложно придумать сценарий, когда один из них не соответствует вашим потребностям.