Подтвердить что ты не робот

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

Есть ли автономные решения для нормализации международного текста в Unicode для надежных идентификаторов и имен файлов в Python?

например. поверните My International Text: åäö в my-international-text-aao

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

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

4b9b3361

Ответ 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 удаляет все акценты из слов.

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