Python 是比使用.replace()更快的正则表达式

Python 是比使用.replace()更快的正则表达式,python,regex,algorithm,Python,Regex,Algorithm,正则表达式会比下面的Python代码更快吗 myStr.replace(","," ").replace("'"," ").replace("-","").replace("_","").replace("["," ").replace("]"," ") 这是否意味着str被迭代了6次(replace()调用的次数)?常规表达式会更快吗?还是相同的算法/方法 这个正则表达式是什么样子的?我相信,在这种情况下,正则表达式会更快,因为每次使用replace时,都必须迭代整个字符串,我想正则表达式几

正则表达式会比下面的Python代码更快吗

myStr.replace(","," ").replace("'"," ").replace("-","").replace("_","").replace("["," ").replace("]"," ")
这是否意味着str被迭代了6次(replace()调用的次数)?常规表达式会更快吗?还是相同的算法/方法


这个正则表达式是什么样子的?

我相信,在这种情况下,正则表达式会更快,因为每次使用
replace
时,都必须迭代整个字符串,我想正则表达式几乎肯定会更快,但您应该做一个简单的基准测试来确定。您拥有的代码执行以下单独的步骤

myStr.replace(","," ")
myStr.replace("'"," ")
myStr.replace("-","")
myStr.replace("_","")
myStr.replace("["," ")
myStr.replace("]"," ")
使用正则表达式可以分两步完成:

re.sub(r"[,'\[\]]", " ", myStr)
re.sub(r"[-_]", "", myStr)

简短回答:使用
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,使用
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我已经更新了布莱尔的计时器小工具,包括我的严肃解决方案(str.translate)。以下是运行标准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
在前面很远。

正则表达式可能会更快。一个好的正则表达式引擎(Python有一个好的引擎)是一种非常快速的方法,可以处理各种各样的字符串转换。不过,除非你真的很擅长正则表达式,否则理解起来会有点困难

通常,当您第一次编写项目时,您应该优化程序员时间(即您的时间),而不是运行时。考虑两个regex调用是否比6个replace调用快的时间最好花在编写更多代码上

如果这个问题是因为您完成了程序(ish)并开始运行它,并且发现它太慢而被提示的,那么现在是考虑这些事情的好时机,尽管您可能需要进行一系列性能度量以找出运行时的花费。很可能程序中的大部分运行时都花在了相对较小的代码部分上,因此一旦您能够识别它们,就可以集中精力使它们更快。我的直觉是,这些替换调用不是这样一个位置。但是,即使是非常有经验的程序员,在编写代码时也不善于预测代码中的“热点”在哪里


如果,OTOH,这个问题是因为您刚刚编写了replace调用,并且想知道是否可以以一种运行更快的方式来完成,那么您可能应该继续编写更多的代码。毕竟,这是编程的乐趣所在。:)

出于兴趣,我使用其他答案中给出的方法编写了一个快速计时测试。为了安全起见,所有的正则表达式都经过了预编译。我的上网本(Ubuntu11.10,Python2.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
两个regex比字符串替换慢10倍,regex/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倍,regex/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))

我建议写一个并测试它。你可能想看看timeit——为了做到这一点。我测试了各种答案的时间安排,并公布了结果。布莱尔的答案中包括了我的笑话答案(一个正则表达式解决方案),但没有包括我的严肃答案(使用str.translate)。我已经补救了。请参阅我的更新答案。-1(a)它相当于
x=myStr.replace(“,”,”);x=x。替换(“,”);etc
(b)分号应该是右括号(c)第一行应该以
myStr=
(d)您可以在一个regexThanks中完成更正。请说明如何在单个正则表达式中执行此操作?
re.sub(r“-\u]”,myStr)
缺少开头的方括号-它应该是
re.sub(r“-\u]”,myStr)
。此外,我还做了一些基准测试(见我的答案),字符串替换速度似乎更快。您误读了OP。下划线和连字符将被替换为空字符串,而逗号、单引号和开合括号将导致空格。在我看来,类似于打字错误:-)更好的解决方案即将出现。注意这个空间。用一个有趣的方法很容易解决