如何执行缓冲搜索和替换?

时间:2011-10-08 14:39:43

标签: python xml buffer replace

我的XML文件包含invalid characters sequences,导致解析失败。它们看起来像。为了解决这个问题,我通过用转义序列替换整个事件来逃避它们: --> !#~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;滑过裂缝。我该如何解决这个问题?如果最后几个看起来像是属于一个字符序列,我想到了更多的字符,但我想到的逻辑非常难看。

2 个答案:

答案 0 :(得分: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数据,所以很多奇怪的随机标点符号可能会自然发生。

答案 1 :(得分:1)

如果序列长度为6个字符,则可以使用具有5个重叠字符的缓冲区。这样,您确定在缓冲区之间不会有任何序列滑动。

以下示例可帮助您进行可视化:

--&#x10
  --

--
   #x10;--

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

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

唯一的问题是串联可能需要整个缓冲区的副本。另一个解决方案是,如果您可以随机访问该文件,则可以使用以下内容进行回放:

f.seek(-5, os.SEEK_CUR)

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