【问题标题】:Fastest way to substitute a set of characters in a string在字符串中替换一组字符的最快方法
【发布时间】:2013-09-21 08:30:23
【问题描述】:

我正在处理一串字节(可以在 10kb 到 3MB 之间的任何位置),我需要过滤掉大约 16 个字节(用其他字节替换它们)

目前我有一个有点像这样的功能..

BYTE_REPLACE = {
  52: 7, # first number is the byte I want to replace
  53: 12, # while the second number is the byte I want to replace it WITH
}
def filter(st):
  for b in BYTE_REPLACE:
    st = st.replace(chr(b),chr(BYTE_REPLACE[b]))
  return st

(为了这个问题而转述的字节列表)

使用 map 的执行时间约为 0.33 秒,而这会缩短 10 倍的时间约为 0.03 秒(两者都在压缩后的 HUGE 字符串上执行)。

虽然任何性能提升都可以忽略不计,但有没有更好的方法来做到这一点?

(我知道存储过滤后的字符串会更加优化。不过,这不是一个选项。我在愚弄 Minecraft Classic 服务器的关卡格式,并且必须过滤掉某些客户端不使用的字节'不支持)

【问题讨论】:

  • 你在字符串中的阅读情况如何?是来自文件系统,还是来自 URL,是否已经全部在内存中?这可能会对最优方法产生很大影响。
  • 它都在内存中可用(并且在每种情况下都直接传递给函数) 在少数情况下,单个字节将传递给这个函数 - 这可以忽略不计,我不介意由它。
  • BYTE_REPLACE 中有多少对?只有 2 个?
  • 16 通常。使用完整列表和相当大的负载测试级别(512*512*256 字节未压缩),完成完全替换需要 0.03 秒(使用 str.replace)
  • string.maketransstring.translate 可能会有所帮助。

标签: python string performance replace


【解决方案1】:

使用str.translate:

Python 3.x

def subs(st):
    return st.translate(BYTE_REPLACE)

示例用法:

>>> subs('4567')
'\x07\x0c67'

Python 2.x

str.translate (Python 2)

import string
k, v = zip(*BYTE_REPLACE.iteritems())
k, v = ''.join(map(chr, k)), ''.join(map(chr, v))
tbl = string.maketrans(k, v)
def subs(st):
    return st.translate(tbl)

【讨论】:

  • 使用 str.translate 的速度大约是我之前使用方法的两倍。
【解决方案2】:

在字符串上查找translate() 方法。这使您可以一次通过字符串执行任意数量的 1 字节转换。使用string.maketrans() 函数构建转换表。如果您通常有 16 对,这应该比执行 1 字节替换 16 次快大约 16 倍。

【讨论】:

    【解决方案3】:

    在您当前的设计中,String.replace() 在字符串 n 上被调用一次,对于每一对。虽然它最有可能是一种高效的算法,但在 3MB 的字符串上它可能会变慢。

    如果在调用此函数时字符串已经包含在内存中,我敢打赌最有效的方法是:

    BYTE_REPLACE = {
      52: 7, # first number is the byte I want to replace
      53: 12, # while the second number is the byte I want to replace it WITH
    }
    def filter(st):
      st = list(st) # Convert string to list to edit in place :/
      for i,s in enumerate(st): #iterate through list
        if ord(s) in BYTE_REPLACE.keys():
            s[i]=chr(BYTE_REPLACE[ord(b)])
      return "".join(st) #return string
    

    一开始有一个很大的操作来创建一个新列表,另一个是转换回字符串,但是由于 Python 字符串在您的设计中是不可变的,因此每次替换都会创建一个新字符串。

    这都是基于猜想,可能是错误的。你会想用你的实际数据来测试它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-09
      • 1970-01-01
      • 2015-01-14
      • 1970-01-01
      相关资源
      最近更新 更多