优化python中的字符串替换

use*_*402 5 python string optimization

我有一个简单的问题.我有一些文本文件,其中的单词已在行尾分割(连字符号).像这样的东西:

toward an emotionless evalu-
ation of objectively gained
Run Code Online (Sandbox Code Playgroud)

我想摆脱连字并再次加入这些词.这可以使用该replace()功能简单快速地完成.但是在某些情况下,连字符后面会有一些额外的换行符.像这样:

end up as a first rate con-


tribution, but that was not
Run Code Online (Sandbox Code Playgroud)

replace()我只是切换到正则表达式而不是堆积几次调用,而是使用re.sub('\-\n+', '', text):

def replace_hyphens(text):
    return re.sub('\-\n+', '', text)
Run Code Online (Sandbox Code Playgroud)

这很有效,但我想知道如何用直接在Python中编码的函数实现相同的结果.这就是我想出的:

def join_hyphens(text):
    processed = ''
    i = 0
    while i < len(text):
        if text[i] == '-':
            while text[i+1] == '\n':
                i += 1
            i += 1
        processed += text[i]
        i += 1
    return processed
Run Code Online (Sandbox Code Playgroud)

但是,与正则表达式相比,当然表现糟糕.如果我在相当长的字符串上超过100次迭代计时,结果就是这里.

join_hyphens done in 2.398ms
replace_hyphens done in 0.021ms
Run Code Online (Sandbox Code Playgroud)

在使用本机Python代码的同时提高性能的最佳方法是什么?


编辑:按照建议切换到列表可以显着提高性能,但与正则表达式相比仍然表现不佳:

def join_hyphens(text):
    processed = []
    i = 0
    while i < len(text):
        if text[i] == '-':
            while text[i+1] == '\n':
                i += 1
            i += 1
        processed.append(text[i])
        i += 1
    return ''.join(processed)
Run Code Online (Sandbox Code Playgroud)

得到:

    join_hyphens done in 1.769ms
    replace_hyphens done in 0.020ms
Run Code Online (Sandbox Code Playgroud)

Jea*_*bre 5

processed += text[i]
Run Code Online (Sandbox Code Playgroud)

processed变大的时候很慢.字符串是不可变的,因此就地添加只是一种幻觉.它没有到位.

有几种选择,一种简单的方法是构建一个列表然后使用str.join:

def join_hyphens(text):
    processed = []
    i = 0
    while i < len(text):
        if text[i] == '-':
            while text[i+1] == '\n':
                i += 1
            i += 1
        processed.append(text[i])
        i += 1
    return "".join(processed)
Run Code Online (Sandbox Code Playgroud)

join预先计算字符串所需的空间,分配(一次性)并加入字符串.一切都是使用python的编译内核完成的,所以速度非常快.

(遗憾的是,你的代码的原生python循环使程序变慢,正则表达式使用编译代码而没有本机python循环,这解释了它更快.str.join在其他环境中非常有用,但是当前的问题可以通过其他几个答案更快地解决这里)


zwe*_*wer 5

派对有点晚了但无论如何...... Python标准库中的所有内容都被认为是原生Python,因为它应该可以在任何Python系统上使用,因此它也包含该re模块.

但是,如果您坚持单独使用Python,而不是逐个遍历字符,则可以使用本机文本搜索来跳过大量文本.这应该会提高性能,在某些情况下甚至会打败regex.当然,"".join()正如其他人所说的那样,字符串连接也更受欢迎:

def join_hyphens(text):
    pieces = []  # a simple chunk buffer store
    head = 0  # our current search head
    finder = text.find  # optimize lookup for str.find
    add_piece = pieces.append  # optimize lookup for list.append
    while True:
        index = finder("-\n", head)  # find the next hyphen
        if index >= 0:  # check if a hyphen was found
            add_piece(text[head:index])  # add the current chunk
            head = index + 2  # move the search head for after the find
            while text[head] == "\n":  # skip new line characters
                head += 1
        else:
            add_piece(text[head:])  # add the last chunk
            break
    return "".join(pieces)  # join the chunks and return them
Run Code Online (Sandbox Code Playgroud)

并测试它:

text = """end up as a first rate con-


tribution, but that was not"""

print(join_hyphens(text))  # end up as a first rate contribution, but that was not
Run Code Online (Sandbox Code Playgroud)