【问题标题】:Skip lines until the next block in a text file if a condition is met in PYthon如果在 PYthon 中满足条件,则跳过行直到文本文件中的下一个块
【发布时间】:2018-01-17 20:04:34
【问题描述】:

我有一个巨大的文本文件,由这样的“块”组成:

block
object pen
fruit apple
people mike
block
electronic laptop
city dallas
fruit banana
object stapler
vehicle car
block
people george
fruit orange
vehicle truck
city austin
object hammer

在每个区块中,随机一行只有一个水果。每个块有不同的行数。我想在这个文件中进行迭代,打印包括水果名称在内的所有内容,然后跳到下一个块。一旦我在一个块中找到水果,检查下一行是否是水果是浪费时间。我只想跳到下一个块,但问题是我不知道该块前面有多少行。所以输出应该是这样的:

block
object pen
the fruit is: apple
block
electronic laptop
city dallas
the fruit is: banana
block
people george
the fruit is: orange

我可以通过两种方式产生这个输出,一种是:

flag = True
with open("sample.txt", "r") as f:
    for line in f.readlines():
        if line.split()[0] == 'fruit':
            print "the fruit is: " + line.split()[1]
            flag = False
        if line.split()[0] == 'block':
            flag = True
        if flag:
            print line

还有两个:

flag = False
with open("sample.txt", "r") as f:
    for line in f.readlines():
        if line.split()[0] == 'fruit':
            print "the fruit is: " + line.split()[1]
            flag = True
        if line.split()[0] == 'block':
            flag = False
        if flag:
            continue
        print line 

但这不是我想要的。我的代码仍然检查每一行是否是水果。我想跳过水果之后的行直到阻塞,然后从那里继续。我怎样才能做到这一点?

【问题讨论】:

  • if flag and line.split()[0] == 'fruit': 只测试标志以避免比较
  • 您的第二段代码已经是您要的...?

标签: python text io text-files


【解决方案1】:
from itertools import takewhile, dropwhile

def not_block(line): return line != 'block\n'
def not_fruit(line): return not line.startswith('fruit ')

with open("sample.txt", "r") as f:
    while True:
        for line in takewhile(not_fruit, dropwhile(not_block(f)):
            print line.rstrip()
        fruitline = next(f, None)
        if fruitline:
            print "the fruit is: " + fruitline.split()[1]
        else:
            break

【讨论】:

  • 史蒂文,感谢您的有用回答,很抱歉忘记“接受”它。
【解决方案2】:

您可以添加一个在找到block 行后触发的内部循环。请注意,这是假设您的数据格式正确(即每个块都有一个水果)。

with open('data.txt') as f:
    for line in f:
        line = line.strip()
        if line == 'block':
            print(line)
            for line in f:
                line = line.strip()
                if line.startswith('fruit '):
                    print('the fruit is:', line.split(None, 1)[1])
                    break
                else:
                    print(line)

您可以做的另一件事涉及更多,但如果数据文件确实很大,则可以更快地使用mmapfind()

【讨论】:

    【解决方案3】:

    说我疯了,但我想用 list comprehensionzip() 对此进行不同的挖掘:

    with open("sample.txt", "r") as file:
        lines = [line.strip('\n') for line in file.readlines()]
    
    blocks = [i for i, j in enumerate(lines) if j == 'block']
    fruits = [i for i, j in enumerate(lines) if 'fruit' in j]
    
    for i, j in zip(blocks, fruits):
        print('\n'.join(lines[i:j+1]))
    

    输出:

    block
    object pen
    fruit apple
    block
    electronic laptop
    city dallas
    fruit banana
    block
    people george
    fruit orange
    

    但这只有在每个block 后面总是跟一个fruit,然后再下一个block 时才有效

    它看起来很漂亮,好吧。不要质疑我选择的武器...

    【讨论】:

    • 这会将所有行预先读取到内存中,这对于大文件可能太慢或使用太多内存。它还会对这些行进行两次迭代。不过,它非常聪明。
    • 啊拍忘了要求的大清单部分。嗯,一切都很有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    • 2017-08-29
    • 2016-10-11
    • 2015-07-09
    • 2019-06-05
    相关资源
    最近更新 更多