在Python中将unicode文本规范化为文件名等

时间:2012-01-28 02:46:28

标签: python unicode plone normalization unicode-normalization

是否有任何标准化的解决方案可以将国际unicode文本规范化为Python中的安全ID和文件名?

E.g。将My International Text: åäö转为my-international-text-aao

plone.i18n确实做得很好,但遗憾的是它取决于zope.securityzope.publisher以及其他一些使其脆弱依赖的软件包。

Some operations that plone.i18n applies

5 个答案:

答案 0 :(得分:33)

你想做的事也被称为“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'

来源: Generating Slugs

对于Python 3: pastebin.com/ft7Yb3KS(感谢@MrPoxipol)。

答案 1 :(得分:4)

解决此问题的方法是决定允许哪些字符(不同的系统对有效标识符有不同的规则。

一旦确定允许哪些字符,请编写 allowed()谓词和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())

此功能非常灵活。它允许您轻松指定用于决定保留哪些文本以及替换或删除哪些文本的规则。

这是一个使用规则的简单示例,“只允许在unicode类别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

答案 2 :(得分:2)

以下将删除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

答案 3 :(得分:2)

我也会在这里抛出我自己的(部分)解决方案:

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字符进行了分解,例如,它将'ä'分解为两个unicode代码点{{ 1}}和U+03B3

另一种方法U+0308返回该特定unicodedata.category(char)的enicode字符类别。类别char包含所有组合重音,因此Mn会删除单词中的所有重音。

但请注意,这只是一个部分解决方案,它摆脱了重音。在此之后,您仍然需要某种类型的白名单。

答案 4 :(得分:0)

我会去

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

很难想出其中一个不符合您需求的情况。