如何在Python

时间:2016-03-03 13:32:02

标签: python regex itertools

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

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

#TYPE Lorem.Text.A
...
#TYPE Lorem.Text.B
...
#TYPE Lorem.Text.C
...

更新

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

来自@Padraic的回答对旧课程最有帮助。

2 个答案:

答案 0 :(得分:3)

您可以使用 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']

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

如果您没有前导空格,并且唯一出现#的地方在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']

答案 1 :(得分:-1)

根据#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...']
>>>