两个分米

时间:2015-05-30 11:18:57

标签: python delimiter

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

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。

5 个答案:

答案 0 :(得分:3)

对于之间的多行,您希望将数据分成几个部分,只需捕获以----- 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打开文件,除非您需要列表,否则不要调用读取行,您可以如上所述迭代文件对象而不将所有内容存储在内存中。

或使用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']

一个文件对象返回它自己的迭代器,所以每当我们迭代或调用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-----

答案 1 :(得分:1)

试试这个:

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)

这将解决您的目的。

答案 2 :(得分:1)

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

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',以便捕获的子字符串总是有一个尾随换行符。

答案 3 :(得分:0)

您可以使用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-----'我们打印它。

答案 4 :(得分:0)

split就好了,不需要其他工具。还要将结束标记及其后的所有内容分开:

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