Python line.split 两个分隔符之间

Python line.split between two delimeters

我有一个包含以下数据的文本文件:

Schema:
  Column Name                   Localized Name                Type    MaxLength
  ----------------------------  ----------------------------  ------  ---------
  Raw                Binary            Binary  16384

Row 1:
  Binary:
-----BEGIN-----
fdsfdsfdasadsad
fsdfafsdafsadfa
fsdafadsfadsfdsa
-----END-----


Row 2:
  Binary:
-----BEGIN-----
fsdfdssd
fdsfadsfasd
fsdafdsa 
-----END-----


Row 3:
  Binary:
-----BEGIN-----
fsdafadsds
fsdafasdsda
fdsafadssad
-----END-----

我需要将“-----BEGIN-----”和“-----END-----”分隔符之间的数据提取到一个数组中。

这是我试过的:

data = open("test_data.txt", 'r')
result = [line.split('-----BEGIN-----') for line in data.readlines()]
print data

然而,这显然会获取“-----BEGIN-----”分隔符之后的所有数据。

如何添加结束分隔符?

请注意文件很大,大约 1GB。

您可以使用 itertools.ifilter :

from itertools import ifilter
with open('a1.txt') as f,open('a1.txt') as g :
    f.next()
    it=f
    print [i.strip() for i in ifilter(lambda x:next(f).strip()=='-----END-----',g)]

结果:

['fdsfdsfdasadsad', 'fsdfdssd', 'fsdafadsds']

如果文件不是很大使用re.findall :

>>> re.findall('-----BEGIN-----\n(.*?)\n-----END-----',open('file_name').read(),re.M|re.DOTALL)
['fdsfdsfdasadsad', 'fsdfdssd', 'fsdafadsds']

或者没有 itertools 你可以使用下面的方法:

with open('a1.txt') as f,open('a1.txt') as g :
    f.next()
    it=f
    for line in g :
        n=next(f)
        try :
            if n.strip()=='-----END-----':
                print line
        except StopIteration:
            break

结果:

fdsfdsfdasadsad

fsdfdssd

fsdafadsds

请注意,文件对象是一个迭代器,您可以在每次迭代中通过 next 函数从中获取下一项。所以我们将文件中每一行的下一行与其下一行(剥离)进行比较,如果它等于 '-----END-----' 我们打印它。

对于 和 之间的多行,您希望将数据分成多个部分,只需捕获以 -----BEGIN-.. 开头的每个块,并继续添加行,直到到达 END:

with open("file.txt") as f:
    out = []
    for line in f:
        if line.rstrip() == "-----BEGIN-----":
            tmp = []
            for line in f:
                if line.rstrip() == "-----END-----":
                    out.append(tmp)
                    break
                tmp.append(line)

这些部分将分成子列表:

 [['fdsfdsfdasadsad\n', 'fsdfafsdafsadfa\n', 'fsdafadsfadsfdsa\n'],   ['fsdfdssd\n', 'fdsfadsfasd\n', 'fsdafdsa \n'], ['fsdafadsds\n', 'fsdafasdsda\n', 'fdsafadssad\n']]

使用 with 打开你的文件,除非你想要一个列表,否则不要调用 readlines,你可以像上面那样遍历文件对象,而不用将所有内容存储在内存中。

或使用 itertools.takewhile 获取部分:

from itertools import takewhile, imap
with open("file.txt") as f:
    f = imap(str.rstrip,f) # use map for python3
    out = [list(takewhile(lambda x: x != "-----END-----",f)) for line in f if line == "-----BEGIN-----"]
    print(out)

[['fdsfdsfdasadsad', 'fsdfafsdafsadfa', 'fsdafadsfadsfdsa'], 
['fsdfdssd', 'fdsfadsfasd', 'fsdafdsa'], 
['fsdafadsds', 'fsdafasdsda', 'fdsafadssad']]

如果您想要一个包含您可以链接的所有单词的列表:

from itertools import takewhile,chain, imap
with open("file.txt") as f:
    f = imap(str.rstrip,f)
    out = chain.from_iterable(takewhile(lambda x: x != "-----END-----",f) for line in f if line == "-----BEGIN-----")
    print(list(out))

['fdsfdsfdasadsad', 'fsdfafsdafsadfa', 'fsdafadsfadsfdsa',
 'fsdfdssd', 'fdsfadsfasd', 'fsdafdsa', 'fsdafadsds', 'fsdafasdsda', 'fdsafadssad']

一个文件对象 returns 它自己的迭代器所以每次我们迭代或调用 takewhile 我们消费行时,takewhile 将继续获取行直到我们命中 -----END---- 然后我们继续迭代直到我们命中另一个 -----BEGIN----- 行,如果行总是以 - 开头并且没有其他行,那么您可以只检查该条件,即 if line[0] == "-"x[0] != "-" 而不是检查整行。

如果您想处理每个部分,您可以使用生成器表达式并处理每个部分的行:

with open("file.txt") as f:
    f = imap(str.rstrip,f)
    out = ((takewhile(lambda x: x != "-----END-----",f)) for line in f if line == "-----BEGIN-----")
    for sec in out:
        print(list(sec))

['fdsfdsfdasadsad', 'fsdfafsdafsadfa', 'fsdafadsfadsfdsa']
['fsdfdssd', 'fdsfadsfasd', 'fsdafdsa']
['fsdafadsds', 'fsdafasdsda', 'fdsafadssad']

如果你想要单个字符串调用 join:

with open("file.txt") as f:
    f = imap(str.rstrip,f)
    st, end = "-----BEGIN-----", "-----END-----"
    out = "".join(chain.from_iterable(takewhile(lambda x: x != end,f)
                                      for line in f if line == st))
    print(out)

输出:

fdsfdsfdasadsadfsdfafsdafsadfafsdafadsfadsfdsafsdfdssdfdsfadsfasdfsdafdsafsdafadsdsfsdafasdsdafdsafadssad

要获得一个保持 -----BEGIN----------END-----

的字符串
with open("out.txt") as f:
    f = imap(str.rstrip,f)
    st, end = "-----BEGIN-----", "-----END-----"
    out = "".join(["{}{}{}".format(st, "".join(takewhile(lambda x: x != end, f)), end)
                                    for line in f if line == st])

输出:

-----BEGIN-----fdsfdsfdasadsadfsdfafsdafsadfafsdafadsfadsfdsa-----END----------BEGIN-----fsdfdssdfdsfadsfasdfsdafdsa-----END----------BEGIN-----fsdafadsdsfsdafasdsdafdsafadssad-----END-----

试试这个:

array1 =[]
with open('test_data.txt','r') as infile:
    copy = False
    for line in infile:
        if line.strip() == "-----BEGIN-----":
            copy = True
        elif line.strip() == "-----END-----":
            copy = False
        elif copy:
            array1.append(line)

这将解决您的目的。

如果您的文件小到足以将整个文件加载到内存中,那么使用正则表达式(aka regex)可能是最好的方法。

import re

beginstr = '\n-----BEGIN-----\n'
endstr = '-----END-----\n'
pat = re.compile(beginstr + '(.*?\n)' + endstr, re.DOTALL)

with open('test_data.txt', 'r') as f:
    data = f.read()

result = pat.findall(data)
for row in result:
    print repr(row)

输出

'fdsfdsfdasadsad\nfsdfafsdafsadfa\nfsdafadsfadsfdsa\n'
'fsdfdssd\nfdsfadsfasd\nfsdafdsa \n'
'fsdafadsds\nfsdafasdsda\nfdsafadssad\n'

该代码创建了一个已编译的正则表达式模式;在这种情况下,这不是绝对必要的,因为我们只使用一次模式,但它确实使代码看起来更整洁,恕我直言。

该正则表达式查找由 'beginstr''\n' + endstr 分隔的子字符串。由于使用了分组括号,findall 调用仅捕获这些定界符之间的内容。我在这些括号内放了一个 '\n',这样捕获的子字符串将始终有一个尾随换行符。

split单独使用就好,不需要其他工具。还要拆分结束标记及其后的所有内容:

with open("file.txt") as f:
    blocks = [part.split('-----END-----')[0].strip()
              for part in f.read().split('-----BEGIN-----')[1:]]