是否有任何标准化的解决方案可以将国际unicode文本规范化为Python中的安全ID和文件名?
E.g。将My International Text: åäö
转为my-international-text-aao
plone.i18n确实做得很好,但遗憾的是它取决于zope.security
和zope.publisher
以及其他一些使其脆弱依赖的软件包。
答案 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)