myStr.replace(","," ").replace("'"," ").replace("-","").replace("_","").replace("["," ").replace("]"," ")
这是否意味着 str 被遍历了 6 次(即 replace() 调用的次数)?使用正则表达式会更快还是相同的算法/方法论?这种情况下正则表达式长什么样子?
myStr.replace(","," ").replace("'"," ").replace("-","").replace("_","").replace("["," ").replace("]"," ")
简短回答:使用 str.translate
,它比标准 Python 发行版中的任何其他替代方法都更快。
长话短说:
这是否意味着 str 被迭代了 6 次(即 replace() 调用的次数)?
还可能是什么呢?
这个正则表达式会是什么样子?
您在 re 文档的哪个部分遇到了困难?
作为一个易于理解的等效方法,请尝试以下内容:
"".join(" " if c in ",'-_[]" else c for c in myStr)
cset = set(",'-_[]")
"".join(" " if c in cset else c for c in myStr)
就速度而言,您应该对与您期望拥有的数据类似的数据进行一些计时。不要忘记包括一个没有这些字符的测试字符串。
更新 这里是实际可用的代码:
>>> import re
>>> myStr = "a,b'c-d_f[g]h"
>>> re.sub(r"[,'\-_[\]]", " ", myStr)
'a b c d f g h'
>>>
更一般地说,为了避免你计算哪些字符需要转义,可以采取以下步骤:
>>> badchars = ",'-_[]"
>>> regex = "[" + re.escape(badchars) + "]"
>>> print regex
[\,\'\-\_\[\]]
>>> re.sub(regex, " ", myStr)
'a b c d f g h'
>>>
更新 2要用一个正则表达式完成 OP 问题似乎要求的内容:
>>> re.sub(r"[,'\-_[\]]", lambda m: "" if m.group(0) in "-_" else " ", myStr)
'a b cdf g h'
更新3为了以最快的方式做到OP问题看起来要求的内容,使用str.translate
# Python 2.X
>>> myStr = "a,b'c-d_f[g]h"
>>> chars2space = ",'[]"
>>> chars2delete = "-_"
>>> table = "".join(" " if chr(i) in chars2space else chr(i) for i in xrange(256))
>>> myStr.translate(table, chars2delete)
'a b cdf g h'
# Python 3.x
>>> myStr = "a,b'c-d_f[g]h"
>>> chars2space = ",'[]"
>>> chars2delete = "-_"
>>> table = dict((ord(c), " ") for c in chars2space)
>>> table.update(dict((ord(c), None) for c in chars2delete))
>>> myStr.translate(table)
'a b cdf g h'
>>>
更新4 我已更新Blair的计时器小工具,加入了我的解决方案(str.translate)。以下是在我的未命名Intel电脑上运行标准win32 Python 2.7.2时的结果:
# input = "a,b'c-d_f[g]h"
String replacement : 0.00000195 seconds per replacement ( 1.00 X)
Borodin: two-regex : 0.00000429 seconds per replacement ( 2.20 X)
John Machin: regex/lambda : 0.00000489 seconds per replacement ( 2.51 X)
John Machin: str.translate : 0.00000042 seconds per replacement ( 0.22 X)
# input *= 100
String replacement : 0.00001612 seconds per replacement ( 1.00 X)
Borodin: two-regex : 0.00015821 seconds per replacement ( 9.82 X)
John Machin: regex/lambda : 0.00036253 seconds per replacement (22.50 X)
John Machin: str.translate : 0.00000424 seconds per replacement ( 0.26 X)
# input *= 1000
String replacement : 0.00012404 seconds per replacement ( 1.00 X)
Borodin: two-regex : 0.00148683 seconds per replacement (11.99 X)
John Machin: regex/lambda : 0.00360127 seconds per replacement (29.03 X)
John Machin: str.translate : 0.00003361 seconds per replacement ( 0.27 X)
# input = "nopunctuation" * 1000 i.e. same length as previous results
String replacement : 0.00002708 seconds per replacement ( 1.00 X)
Borodin: two-regex : 0.00018181 seconds per replacement ( 6.71 X)
John Machin: regex/lambda : 0.00008235 seconds per replacement ( 3.04 X)
John Machin: str.translate : 0.00001780 seconds per replacement ( 0.66 X)
看起来str.translate
是最先进的。
出于兴趣,我使用timeit
编写了一个快速的计时测试,测试了其他答案中给出的方法。为了安全起见,所有正则表达式都已预编译。以下是我的净书(Ubuntu 11.10,Python 2.7.2)上的结果,从快到慢:
String replacement: 8.556e-06 seconds per replacement
Borodin's two-regex solution: 1.979e-05 seconds per replacement
John Machin's regex/lambda solution: 2.623e-05 seconds per replacement
因此,两个正则表达式的解决方案比简单的字符串替换慢2.3倍,而John Machin的单个正则表达式和lambda函数的解决方案比字符串替换慢3.06倍。
为了测试一个更长的字符串,我将原始字符串连接了100次:
String replacement: 7.600e-05 seconds per replacement
Borodin's two-regex solution: 7.894e-04 seconds per replacement
John Machin's regex/lambda solution: 1.909e-03 seconds per replacement
使用正则表达式替换字符串速度比字符串替换慢10倍,使用正则表达式/lambda表达式慢25倍。
如果将原始输入串连接1000次,则:
String replacement: 5.396e-04 seconds per replacement
Borodin's two-regex solution: 8.584e-03 seconds per replacement
John Machin's regex/lambda solution: 2.094e-02 seconds per replacement
现在,使用正则表达式的速度已经比字符串替换慢了15.9倍,而使用正则表达式/lambda的速度更慢,达到了38.8倍。
随着输入的增加,正则表达式的速度似乎越来越慢。我猜想这是因为正则表达式需要逐个字符扫描输入,而且它们执行的复杂测试比多次循环慢得多。使用lambda函数用单个正则表达式替换字符似乎比使用两个正则表达式要慢得多。
如果其他人想在自己的计算机上检查时间,请使用以下代码:
import sys
import timeit
# How many times to test each method.
n = 1000
# String to test with.
test_str = "a,b'c-d_f[g]h"
# Correct output.
correct = "a b cdf g h"
# Uncomment to try longer strings.
#test_str *= 100
#correct *= 100
# Setup code (i.e., code which shouldn't be included in the timings).
setup = """
import re
# Borodin's two-regex solution.
bre1 = re.compile(r"[,'\[\]]")
bre2 = re.compile(r"[-_]")
# John Machin's solution.
jmre = re.compile(r"[,'\-_[\]]")
repl = lambda m: "" if m.group(0) in "-_" else " "
test_str=\"{0:s}\"""".format(test_str)
# The methods.
methods = {
'String replacement': 'result=test_str.replace(","," ").replace("\'"," ").replace("-","").replace("_","").replace("["," ").replace("]"," ")',
'Borodin\'s two-regex solution': 'result=bre2.sub("", bre1.sub(" ", test_str))',
'John Machin\'s regex/lambda solution': 'result=jmre.sub(repl, test_str)',
}
# Execute the setup so we can test for correctness.
exec(setup)
for method, code in methods.items():
# Check the code gives correct results.
exec(code)
if(result != correct):
sys.stdout.write('{0} gave incorrect output: {1}\n'.format(method, result))
continue
# Time it.
t = timeit.timeit(code, setup, number=n)
sys.stdout.write('{0}: {1:.3e} seconds per replacement\n'.format(method, t/n))
我相信,在这种情况下,正则表达式会更快,因为使用 replace
每次都必须迭代整个字符串。
myStr.replace(","," ")
myStr.replace("'"," ")
myStr.replace("-","")
myStr.replace("_","")
myStr.replace("["," ")
myStr.replace("]"," ")
使用正则表达式可以分两步完成:
re.sub(r"[,'\[\]]", " ", myStr)
re.sub(r"[-_]", "", myStr)
x = myStr.replace(","," "); x = x.replace("'"," ");
等等
(b) 分号应该改为右括号
(c) 第一行应该以 myStr =
开始
(d) 你可以用一个正则表达式完成它。 - John Machinre.sub(r"-_]", "", myStr)
缺少左方括号 - 应该是 re.sub(r"[-_]", "", myStr)
。另外,我进行了一些基准测试(请参见我的答案),似乎字符串替换仍然更快。 - Blair