Python 字符串清理与处理(带重音字符)
我有一个数据库,里面全是名字,比如:
John Smith
Scott J. Holmes
Dr. Kaplan
Ray's Dog
Levi's
Adrian O'Brien
Perry Sean Smyre
Carie Burchfield-Thompson
Björn Árnason
里面有一些外文名字,带有重音符号,需要把这些名字转换成没有重音的字符。
我想把完整的名字(去掉像 " ' " 和 "-" 这样的字符)转换成用户登录名,比如:
john.smith
scott.j.holmes
dr.kaplan
rays.dog
levis
adrian.obrien
perry.sean.smyre
carie.burchfieldthompson
bjorn.arnason
到目前为止,我已经有了:
Fullname.strip() # get rid of leading/trailing white space
Fullname.lower() # make everything lower case
... # after bad chars converted/removed
Fullname.replace(' ', '.') # replace spaces with periods
5 个回答
下面这个函数是通用的:
import unicodedata
def not_combining(char):
return unicodedata.category(char) != 'Mn'
def strip_accents(text, encoding):
unicode_text= unicodedata.normalize('NFD', text.decode(encoding))
return filter(not_combining, unicode_text).encode(encoding)
# in a cp1252 environment
>>> print strip_accents("déjà", "cp1252")
deja
# in a cp1253 environment
>>> print strip_accents("καλημέρα", "cp1253")
καλημερα
很明显,你需要知道你的字符串是用什么编码的。
如果你不怕安装第三方模块,可以看看这个Python版本的Perl模块Text::Unidecode
(它也在pypi上)。
这个模块的功能很简单,就是用一个查找表来转换字符。我看过代码,感觉非常简单。所以我想它应该可以在任何操作系统和Python版本上运行(希望如此)。而且把它和你的应用打包在一起也很容易。
使用这个模块,你就不用手动创建查找表了(这样可以减少不完整的风险)。
这个模块相比于Unicode标准化技术的好处在于:Unicode标准化并不会替换所有字符。比如像“æ”这样的字符,Unicode标准化会把它视为“小写字母”(Ll)。这意味着使用normalize
方法时,你既得不到替换字符,也得不到有用的提示。可惜的是,这个字符在ASCII中是无法表示的。所以你会遇到错误。
前面提到的模块在这方面做得更好。它会把“æ”替换成“ae”。这实际上是有用的,也很合理。
我见过的最令人印象深刻的地方是,它的功能更强大。它甚至可以大部分正确地替换日语的假名字符。例如,它会把“は”替换成“ha”。这完全没问题。不过它并不是万无一失的,因为当前版本把“ち”替换成“ti”而不是“chi”。所以对于一些比较特殊的字符,你需要小心处理。
使用这个模块非常简单:
from unidecode import unidecode
var_utf8 = "æは".decode("utf8")
unidecode( var_utf8 ).encode("ascii")
>>> "aeha"
请注意,我和这个模块没有直接关系。只是我觉得它非常有用。
编辑:我提交的补丁修复了关于日语假名的错误。我只修复了我能立刻发现的问题,可能还有一些我没注意到。
看看这个链接 [redacted]
这里是页面上的代码
def latin1_to_ascii (unicrap):
"""This replaces UNICODE Latin-1 characters with
something equivalent in 7-bit ASCII. All characters in the standard
7-bit ASCII range are preserved. In the 8th bit range all the Latin-1
accented letters are stripped of their accents. Most symbol characters
are converted to something meaningful. Anything not converted is deleted.
"""
xlate = {
0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A',
0xc6:'Ae', 0xc7:'C',
0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E',
0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I',
0xd0:'Th', 0xd1:'N',
0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O',
0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U',
0xdd:'Y', 0xde:'th', 0xdf:'ss',
0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a',
0xe6:'ae', 0xe7:'c',
0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e',
0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i',
0xf0:'th', 0xf1:'n',
0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o',
0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u',
0xfd:'y', 0xfe:'th', 0xff:'y',
0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}',
0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}',
0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}',
0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}',
0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'",
0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}',
0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>',
0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?',
0xd7:'*', 0xf7:'/'
}
r = ''
for i in unicrap:
if xlate.has_key(ord(i)):
r += xlate[ord(i)]
elif ord(i) >= 0x80:
pass
else:
r += i
return r
# This gives an example of how to use latin1_to_ascii().
# This creates a string will all the characters in the latin-1 character set
# then it converts the string to plain 7-bit ASCII.
if __name__ == '__main__':
s = unicode('','latin-1')
for c in range(32,256):
if c != 0x7f:
s = s + unicode(chr(c),'latin-1')
print 'INPUT:'
print s.encode('latin-1')
print
print 'OUTPUT:'
print latin1_to_ascii(s)