【问题标题】:How can I perform a buffered search and replace?如何执行缓冲搜索和替换?
【发布时间】:2011-12-03 14:15:29
【问题描述】:

我有包含 invalid characters sequences 的 XML 文件,这会导致解析失败。它们看起来像。为了解决这个问题,我通过用转义序列替换整个事情来逃避它们: --> !#~10^。然后在我完成解析后,我可以将它们恢复到原来的样子。

buffersize = 2**16   # 64 KB buffer

def escape(filename):
    out = file(filename + '_esc', 'w') 

    with open(filename, 'r') as f:
        buffer = 'x'     # is there a prettier way to handle the first one?
        while buffer != '':
            buffer = f.read(buffersize)
            out.write(re.sub(r'&#x([a-fA-F0-9]+);', r'!#~\1^', buffer))

    out.close()

文件非常大,所以我必须使用缓冲(mmap 给了我一个MemoryError)。因为缓冲区具有固定大小,所以当缓冲区恰好小到足以拆分序列时,我会遇到问题。想象一下缓冲区大小是8,文件是这样的:

 123456789
 hello!&x10;

缓冲区只会读取hello!&x,允许&x10; 溜过裂缝。我该如何解决这个问题?如果最后几个看起来可以属于一个字符序列,我想得到更多的字符,但是我想到的逻辑很丑。

【问题讨论】:

    标签: python xml buffer replace


    【解决方案1】:

    如果您的序列长度为 6 个字符,则可以使用包含 5 个重叠字符的缓冲区。这样,您就可以确定缓冲区之间不会出现任何序列。

    这是一个帮助您形象化的示例:

    --&#x10
      --
    
    --
       #x10;--
    

    至于实现,只需将最后一个缓冲区的最后 5 个字符添加到新缓冲区:

    buffer = buffer[-5:] + f.read(buffersize)
    

    唯一的问题是连接可能需要整个缓冲区的副本。如果您可以随机访问该文件,另一种解决方案是使用以下命令倒带一点:

    f.seek(-5, os.SEEK_CUR)
    

    在这两种情况下,您都必须稍微修改脚本以处理第一次迭代。

    【讨论】:

      【解决方案2】:

      首先,不必费心读写文件,您可以创建一个类似文件的对象来包装打开的文件,并在解析器处理数据之前对其进行处理。其次,您的缓冲可以只处理读取字节的结尾。这是一些工作代码:

      class Wrapped(object):
          def __init__(self, f):
              self.f = f
              self.buffer = ""
      
          def read(self, size=0):
              buf = self.buffer + self.f.read(size)
              buf = buf.replace("!", "!!")
              buf = re.sub(r"&(#x[0-9a-fA-F]+;)", r"!\1", buf)
              # If there's an ampersand near the end, hold onto that piece until we
              # have more, to be sure we don't miss one.
              last_amp = buf.rfind("&", -10, -1)
              if last_amp > 0:
                  self.buffer = buf[last_amp:]
                  buf = buf[:last_amp]
              else:
                  self.buffer = ""
              return buf
      

      然后在你的代码中,替换这个:

      it = ET.iterparse(file(xml, "rb"))
      

      用这个:

      it = ET.iterparse(Wrapped(file(xml, "rb")))
      

      第三,我用“!”和“!”替换了“&”。使用“!!”,因此您可以在解析后修复它们,并且您不会指望晦涩的序列。这毕竟是 Stack Overflow 数据,自然会出现很多奇怪的随机标点符号。

      【讨论】:

      • 包装器是个好主意...但是如果您替换“!”和 ”!!”然后是你原来的“!!”将替换为“!”。我不认为有什么好办法。
      • 替换“!”和 ”!!”意味着在您的最终输出中,每个“!”是一个转义字符,你可以看下一个字符来决定做什么:“!” next表示只输出一个“!”,“#”表示输出一个数字实体。这与格式字符串中的“%”和“%%”相同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-05
      • 2012-01-03
      • 1970-01-01
      • 2015-02-15
      • 1970-01-01
      • 2022-10-07
      • 1970-01-01
      相关资源
      最近更新 更多