Python:高效替换重音符(é变为e)、移除[^a-zA-Z\d\s]并小写化的方法
我正在使用Python 3.3,想要做以下几件事:
- 把一些特殊的字母,比如带重音的字母(像é)和带抑扬符的字母(像ô),替换成它们的基本字母(比如把ô变成o)
- 去掉所有非字母数字的字符,只保留字母、数字和字母数字之间的空格
- 把所有字母转换成小写
这是我目前的代码:
mystring_modified = mystring.replace('\u00E9', 'e').replace('\u00F4', 'o').lower()
alphnumspace = re.compile(r"[^a-zA-Z\d\s]")
mystring_modified = alphnumspace.sub('', mystring_modified)
我该如何改进这个代码呢?效率是个大问题,尤其是因为我现在是在一个循环里进行这些操作:
# Pseudocode
for mystring in myfile:
mystring_modified = # operations described above
mylist.append(mystring_modified)
这些文件大约有20万个字符。
2 个回答
5
你可以使用 str.translate 这个方法:
import collections
import string
table = collections.defaultdict(lambda: None)
table.update({
ord('é'):'e',
ord('ô'):'o',
ord(' '):' ',
ord('\N{NO-BREAK SPACE}'): ' ',
ord('\N{EN SPACE}'): ' ',
ord('\N{EM SPACE}'): ' ',
ord('\N{THREE-PER-EM SPACE}'): ' ',
ord('\N{FOUR-PER-EM SPACE}'): ' ',
ord('\N{SIX-PER-EM SPACE}'): ' ',
ord('\N{FIGURE SPACE}'): ' ',
ord('\N{PUNCTUATION SPACE}'): ' ',
ord('\N{THIN SPACE}'): ' ',
ord('\N{HAIR SPACE}'): ' ',
ord('\N{ZERO WIDTH SPACE}'): ' ',
ord('\N{NARROW NO-BREAK SPACE}'): ' ',
ord('\N{MEDIUM MATHEMATICAL SPACE}'): ' ',
ord('\N{IDEOGRAPHIC SPACE}'): ' ',
ord('\N{IDEOGRAPHIC HALF FILL SPACE}'): ' ',
ord('\N{ZERO WIDTH NO-BREAK SPACE}'): ' ',
ord('\N{TAG SPACE}'): ' ',
})
table.update(dict(zip(map(ord,string.ascii_uppercase), string.ascii_lowercase)))
table.update(dict(zip(map(ord,string.ascii_lowercase), string.ascii_lowercase)))
table.update(dict(zip(map(ord,string.digits), string.digits)))
print('123 fôé BAR҉'.translate(table,))
这样会得到
123 foe bar
不过,这种方法的缺点是你需要列出所有你想要转换的特殊带重音的字符。@gnibbler 的方法代码量会少一些。
但好的一面是,str.translate
方法应该会比较快,而且一旦设置好 table
,它可以一次性处理你所有的需求(比如小写、删除字符和去掉重音)。
顺便说一下,一个包含20万字符的文件并不算大。所以,把整个文件读入一个 str
中,然后一次性进行转换会更有效率。
34
>>> import unicodedata
>>> s='éô'
>>> ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))
'eo'
另外,可以看看 unidecode
Unidecode 提供了一种折中的方法:它的 unidecode() 函数可以处理 Unicode 数据,并试图用 ASCII 字符来表示这些数据(也就是那些在 0x00 到 0x7F 之间的通用可显示字符)。在将两种字符集进行映射时,它会选择一些人类在使用美国键盘时可能会选择的折中方案。
生成的 ASCII 表示质量各不相同。对于西方语言来说,效果应该在完美和良好之间。但对于中文、日文或韩文这样的语言,音译(也就是用罗马字母表达其他书写系统中的发音)是个非常复杂的问题,这个库甚至不打算去解决这个问题。它只是在字符之间进行无上下文的逐个映射。因此,一个简单的经验法则是:你要音译的文字越远离拉丁字母,音译的效果就会越差。
需要注意的是,这个模块通常比简单地去掉字符的重音符号(这可以通过 Python 的内置函数来实现)效果要好。它是基于经过手动调整的字符映射,这些映射还包含了符号和非拉丁字母的 ASCII 近似值。