Python:正则表达式跨文件块边界匹配

时间:2017-05-27 01:53:10

标签: python regex boundary

巨大的纯文本数据文件

我使用python以块的形式读取了一个巨大的文件。然后我在那个块上应用正则表达式。基于标识符标记,我想提取相应的值。由于块大小,块边界处缺少数据。

要求:

  • 必须以块的形式读取文件。
  • 块大小必须小于 或等于1 GiB。


Python代码示例

identifier_pattern = re.compile(r'Identifier: (.*?)\n')
with open('huge_file', 'r') as f:
    data_chunk = f.read(1024*1024*1024)
    m = re.findall(identifier_pattern, data_chunk)


块数据示例

好:与标识数相等的标记数

  

标识符:值
标识符:值
标识符:值
  标识符:值


由于块大小,您会遇到如下所列的不同边界问题。第三个标识符返回一个不完整的值," v"而不是"价值"。下一个块包含" alue"。这会在解析后导致丢失数据。

错误:标识符值不完整

  

标识符:值
标识符:值
标识符:v


你如何解决像这样的块边界问题?

5 个答案:

答案 0 :(得分:3)

假设这是你的确切问题,你可能只需调整你的正则表达式并逐行读取(它不会将整个文件加载到内存中):

import re
matches = []
identifier_pattern = re.compile(r'Identifier: (.*?)$')
with open('huge_file') as f:
    for line in f:
        matches += re.findall(identifier_pattern, line)

print("matches", matches)

答案 1 :(得分:2)

你可以控制块形成并使其接近1024 * 1024 * 1024,在这种情况下你可以避免遗漏部分:

import re


identifier_pattern = re.compile(r'Identifier: (.*?)\n')
counter = 1024 * 1024 * 1024
data_chunk = ''
with open('huge_file', 'r') as f:
    for line in f:
        data_chunk = '{}{}'.format(data_chunk, line)
        if len(data_chunk) > counter:
            m = re.findall(identifier_pattern, data_chunk)
            print m.group()
            data_chunk = ''
    # Analyse last chunk of data
    m = re.findall(identifier_pattern, data_chunk)
    print m.group()

或者,你可以在不同起始点read的同一个文件上进行两次(第一次从0开始,第二次从第一次迭代中收集的匹配字符串的最大长度开始),将结果存储为字典,其中key=[start position of matched string in file],每个迭代的位置都是相同的,因此合并结果不会有问题,但我认为按照匹配字符串的起始位置和长度进行合并会更准确。

祝你好运!

答案 2 :(得分:1)

如果文件基于行file对象是懒惰的行生成器,它会将文件加载到内存行按行(在块中),基于此,您可以使用:

import re
matches = []
for line in open('huge_file'):
    matches += re.findall("Identifier:\s(.*?)$", line)

答案 3 :(得分:0)

我的解决方案与杰克的答案非常相似:

#!/usr/bin/env python3

import re

identifier_pattern = re.compile(r'Identifier: (.*)$')

m = []
with open('huge_file', 'r') as f:
    for line in f:
        m.extend(identifier_pattern.findall(line))

您可以使用正则表达式API的另一部分来获得相同的结果:

#!/usr/bin/env python3

import re

identifier_pattern = re.compile(r'Identifier: (.*)$')

m = []
with open('huge_file', 'r') as f:
    for line in f:
        pattern_found = identifier_pattern.search(line)
        if pattern_found:
            value_found = pattern_found.group(0)
            m.append(value_found)

我们可以使用generator expressionlist comprehension

进行简化
#!/usr/bin/env python3

import re

identifier_pattern = re.compile(r'Identifier: (.*)$')

with open('huge_file', 'r') as f:
    patterns_found = (identifier.search(line) for line in f)
    m = [pattern_found.group(0) 
         for pattern_found in patterns_found if pattern_found]

答案 4 :(得分:0)

如果知道匹配结果字符串的长度,我认为最简单的方法是将最后一块的字节缓存在边界周围。

假设结果的长度为3,保留最后一块的最后2个字符,然后将其添加到新块中进行匹配。

伪代码:

regex  pattern
string boundary
int    match_result_len

for chunk in chunks:
    match(boundary + chunk, pattern)
    boundary = chunk[-(match_result_len - 1):]