Python - 高效方法去除所有非字母并用下划线替换

11 投票
5 回答
13125 浏览
提问于 2025-04-15 18:41
def format_title(title):  
  ''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', title.strip()))

有没有更快的方法?

5 个回答

2

与其使用 (x.isupper() or x.islower()),你可以直接用 x.isalpha()。这个 isalpha() 方法可能会对 '_' 返回 True(我记不清楚它是否会这样做),但即使是这样,你也只是把 '_' 替换成 '_',所以也没什么坏处。(感谢 KennyTM 提醒这一点。)

17
import re
title = re.sub("[\W\d]", "_", title.strip())

应该会更快。

如果你想把一连串相邻的非字母字符替换成一个下划线,可以使用

title = re.sub("[\W\d]+", "_", title.strip())

这个方法,它甚至更快。

我刚刚做了个时间对比:

C:\>python -m timeit -n 100 -s "data=open('test.txt').read().strip()" "''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', data))"
100 loops, best of 3: 4.51 msec per loop

C:\>python -m timeit -n 100 -s "import re; regex=re.compile('[\W\d]+'); data=open('test.txt').read().strip()" "title=regex.sub('_',data)"
100 loops, best of 3: 2.35 msec per loop

这个方法也适用于Unicode字符串(在Python 3中,\W可以匹配任何不是Unicode单词字符的字符。在Python 2中,你还需要额外设置UNICODE标志才能使用)。

20

更快的方法是使用 str.translate() 这个函数。这个方法比你之前的方法快大约50倍。

# You only need to do this once
>>> title_trans=''.join(chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256))

>>> "abcde1234!@%^".translate(title_trans)
'abcde________'

# Using map+lambda
$ python -m timeit '"".join(map(lambda x: x if (x.isupper() or x.islower()) else "_", "abcd1234!@#$".strip()))'
10000 loops, best of 3: 21.9 usec per loop

# Using str.translate
$ python -m timeit -s 'titletrans="".join(chr(c) if chr(c).isupper() or chr(c).islower() else "_" for c in range(256))' '"abcd1234!@#$".translate(titletrans)'
1000000 loops, best of 3: 0.422 usec per loop

# Here is regex for a comparison
$ python -m timeit -s 'import re;transre=re.compile("[\W\d]+")' 'transre.sub("_","abcd1234!@#$")'
100000 loops, best of 3: 3.17 usec per loop

这里有一个适用于unicode的版本。

# coding: UTF-8

def format_title_unicode_translate(title):
    return title.translate(title_unicode_trans)

class TitleUnicodeTranslate(dict):
    def __missing__(self,item):
        uni = unichr(item)
        res = u"_"
        if uni.isupper() or uni.islower():
            res = uni
        self[item] = res
        return res
title_unicode_trans=TitleUnicodeTranslate()

print format_title_unicode_translate(u"Metallica Μεταλλικα")

注意,希腊字母会被算作大写和小写字母,所以它们不会被替换。如果你想要替换它们,只需把条件改成:

        if item<256 and (uni.isupper() or uni.islower()):

撰写回答