Нормализация текста unicode в имена файлов и т. д. в Python

есть ли standalonenish решения для нормализации международной кодировке Юникод для просмотра идентификаторов и имен файлов в Python?

Е. Г. включить My International Text: åäö до my-international-text-aao

и Plone.как i18n делает действительно хорошую работу, но, к сожалению, это зависит от zope.security и zope.publisher и некоторые другие пакеты делают его хрупкой зависимостью.

некоторые операции, которые plone.как i18n применяется

5 ответов


то, что вы хотите сделать, также известно как "slugify" строку. Вот возможное решение:

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

использование:

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


способ решить эту проблему - принять решение о том, какие символы разрешены (разные системы имеют разные правила для допустимых идентификаторов.

как только вы решите, какие символы разрешены, напишите разрешена() предикат и подкласс dict для использования с .перевести:

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

следующее удалит акценты из любых символов, которые 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 из файла, который вы связаны, что.


я тоже брошу свое (частичное) решение здесь:

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) выполняет декомпозицию символов Юникода, например, разбивает " ä " на две кодовые точки Юникода U+03B3 и U+0308.

другой способ, unicodedata.category(char), возвращает категорию символов enicode для этого конкретного char. Категория Mn содержит все комбинирующие акценты, таким образом deaccent удаляет все акценты от слов.

но обратите внимание, что это только частичное решение, оно избавляется от акцентов. Вам все еще нужен какой-то белый список символов, которые вы хотите разрешить после этого.


Я бы пошел с

https://pypi.python.org/pypi?%3Aaction=search&term=slug

трудно придумать сценарий, где один из них не соответствует вашим потребностям.