如何通过 Python 中的字符串定界符将文件拆分成块

How to split file into chunks by string delimiter in Python

我需要将一个可能很大的 csv 文件上传到我的应用程序中。该文件的每个部分都由 #TYPE * 指示。我应该如何将它分成块并对每个块进行进一步处理?每个块都是 headers 后跟所有值的列表。

现在我已经编写了单个块的处理,但我不确定如何对每个块进行操作。我认为正则表达式操作将是最佳选择,因为 #TYPE *.

的常量 return
#TYPE Lorem.Text.A
...
#TYPE Lorem.Text.B
...
#TYPE Lorem.Text.C
...

更新

此解决方案已从将所有部分保存在一个文件中更改为将所有部分保存到单独的文件中并将它们压缩到一个 zip 文件中。此 zip 文件由 python 读取并进一步分析。如果有人对此解释感兴趣,请给我留言,我会更新这个问题。

@Padraic 的回答对老课程最有帮助。

根据#TYPE

之前存在的换行字符进行拆分
chunks = re.split(r'\n(?=#TYPE\b *)', f.read())

示例:

>>> import re
>>> s = '''#TYPE Lorem.Text.A
...
#TYPE Lorem.Text.B
...
#TYPE Lorem.Text.C
...'''
>>> re.split(r'\n(?=#TYPE *)', s)
['#TYPE Lorem.Text.A\n...', '#TYPE Lorem.Text.B\n...', '#TYPE Lorem.Text.C\n...']
>>> 

您可以使用 groupby 假设各部分由以 #TYPE:

开头的行分隔
from itertools import groupby, chain


def get_sections(fle):
    with open(fle) as f:
        grps = groupby(f, key=lambda x: x.lstrip().startswith("#TYPE"))
        for k, v in grps:
            if k:
                yield chain([next(v)], (next(grps)[1]))  # all lines up to next #TYPE

您可以在迭代时获取每个部分:

In [13]: cat in.txt
#TYPE Lorem.Text.A
first
#TYPE Lorem.Text.B
second
#TYPE Lorem.Text.C
third

In [14]: for sec in get_sections("in.txt"):
   ....:     print(list(sec))
   ....:     
['#TYPE Lorem.Text.A\n', 'first\n']
['#TYPE Lorem.Text.B\n', 'second\n']
['#TYPE Lorem.Text.C\n', 'third\n']

如果没有其他行以 # 开头,那么仅此一项就足以在 startswith 中使用,您的模式中没有任何复杂的东西,因此它不是正则表达式的真正用例。这也一次只存储一个部分而不是整个文件到内存中。

如果您没有前导空格并且 # 出现的唯一位置是在 TYPE 之前,则只需调用 groupby:

就足够了
from itertools import groupby, chain


def get_sections(fle):
    with open(fle) as f:
        grps = groupby(f)
        for k, v in grps:
            if k:
                yield chain([next(v)], (next(grps)[1]))  # all lines up to next #TYPE

如果开头有一些元数据,您可以使用 dropwhile 跳过行,直到我们点击 #Type 然后只是分组:

from itertools import groupby, chain, dropwhile


def get_sections(fle):
    with open(fle) as f:
        grps = groupby(dropwhile(lambda x: not x.startswith("#"), f))
        for k, v in grps:
            if k:
                yield chain([next(v)], (next(grps)[1]))  # all lines up to next #TYPE

演示:

In [16]: cat in.txt
meta
more meta
#TYPE Lorem.Text.A
first
#TYPE Lorem.Text.B
second
second
#TYPE Lorem.Text.C
third

In [17]: for sec in get_sections("in.txt"):
            print(list(sec))
   ....:     
['#TYPE Lorem.Text.A\n', 'first\n']
['#TYPE Lorem.Text.B\n', 'second\n', 'second\n']
['#TYPE Lorem.Text.C\n', 'third\n']