【问题标题】:How to only read lines in a text file after a certain string?如何仅在某个字符串之后读取文本文件中的行?
【发布时间】:2015-03-04 13:09:55
【问题描述】:

我想将文本文件中特定字符串之后的所有行读入字典。我想对数千个文本文件执行此操作。

我可以使用以下代码(来自this answer)识别并打印出特定的字符串('Abstract'):

for files in filepath:
    with open(files, 'r') as f:
        for line in f:
            if 'Abstract' in line:
                print line;

但是我如何告诉 Python 开始读取仅在字符串之后的行呢?

【问题讨论】:

    标签: python string file


    【解决方案1】:

    当你到达你想开始的那一行时,再开始另一个循环:

    for files in filepath:
        with open(files, 'r') as f:
            for line in f:
                if 'Abstract' in line:                
                    for line in f: # now you are at the lines you want
                        # do work
    

    文件对象是它自己的迭代器,所以当我们到达其中包含'Abstract' 的行时,我们会从该行继续迭代,直到我们使用完迭代器。

    一个简单的例子:

    gen = (n for n in xrange(8))
    
    for x in gen:
        if x == 3:
            print('Starting second loop')
            for x in gen:
                print('In second loop', x)
        else:
            print('In first loop', x)
    

    生产:

    In first loop 0
    In first loop 1
    In first loop 2
    Starting second loop
    In second loop 4
    In second loop 5
    In second loop 6
    In second loop 7
    

    您还可以使用itertools.dropwhile 将行消耗到您想要的点:

    from itertools import dropwhile
    
    for files in filepath:
        with open(files, 'r') as f:
            dropped = dropwhile(lambda _line: 'Abstract' not in _line, f)
            next(dropped, '')
            for line in dropped:
                    print(line)
    

    【讨论】:

    • 它有效,但有点奇怪,你不觉得吗?任何不了解生成器如何工作的人都会对为什么产生正确的输出感到头疼。
    • @Kroltan,我想看python的人都知道python代码是如何工作的。这是非常基本的python
    • 好吧,但我不太确定 OP 是否意识到这一点。
    • 这对我不起作用......它只是不起作用它每次都从头开始......循环被嵌入并且它仍然从头开始
    • @KyleBurkett,这根本不可能,无论你从迭代器中消耗什么都消失了,如果它不起作用,那么你做错了而不是代码,所以也许调试你的代码而不是 downvoting 可能是更好的选择。
    【解决方案2】:

    使用布尔值忽略到该点的行:

    found_abstract = False
    for files in filepath:
        with open(files, 'r') as f:
            for line in f:
                if 'Abstract' in line:
                    found_abstract = True
                if found_abstract:
                    #do whatever you want
    

    【讨论】:

      【解决方案3】:

      您可以在这里使用itertools.dropwhileitertools.islice,这是一个伪示例:

      from itertools import dropwhile, islice
      
      for fname in filepaths:
          with open(fname) as fin:
              start_at = dropwhile(lambda L: 'Abstract' not in L.split(), fin)
              for line in islice(start_at, 1, None): # ignore the line still with Abstract in
                  print line
      

      【讨论】:

        【解决方案4】:

        对我来说,下面的代码更容易理解。

        with open(file_name, 'r') as f:
            while not 'Abstract' in next(f):
                pass
            for line in f:
                #line will be now the next line after the one that contains 'Abstract'
        

        【讨论】:

        • 我收到 AttributeError: '_io.TextIOWrapper' 对象没有属性 'next'
        • Hoy 可能正在使用 python 3.0。试试next(f) 而不是f.next() 并告诉我它是否有效。
        • 当我使用 str 变量而不是硬编码值时,我得到一个停止迭代错误:(
        • 我不认为使用字符串变量会导致错误。这可能是因为文件中不存在该字符串。如果是这样,可能是文件的编码引入了一些问题。
        【解决方案5】:

        澄清一下,您的代码已经“读取”了所有行。要开始“关注”某个点之后的行,您可以设置一个布尔标志来指示是否应忽略行,并在每一行进行检查。

        pay_attention = False
        for line in f:
            if pay_attention:
                print line
            else:  # We haven't found our trigger yet; see if it's in this line
                if 'Abstract' in line:
                    pay_attention = True
        

        如果您不介意重新排列代码,也可以使用两个部分循环:一个循环在您找到触发短语 ('Abstract') 后终止,另一个循环读取所有以下内容线。这种方法更简洁一些(而且速度非常快)。

        for skippable_line in f:  # First skim over all lines until we find 'Abstract'.
            if 'Abstract' in skippable_line:
                break
        for line in f:  # The file's iterator starts up again right where we left it.
            print line
        

        这样做的原因是open 返回的文件对象的行为类似于generator,而不是一个列表:它只在请求时生成值。因此,当第一个循环停止时,文件的内部位置设置在第一个“未读”行的开头。这意味着当您进入第二个循环时,您看到的第一行是触发break 的那一行之后的第一行。

        【讨论】:

          【解决方案6】:

          猜测字典是如何涉及的,我会这样写:

          lines = dict()
          for filename in filepath:
             with open(filename, 'r') as f:
                 for line in f:
                     if 'Abstract' in line:
                         break
                 lines[filename] = tuple(f)
          

          因此,对于每个文件,您的字典都包含一个行元组。

          这是有效的,因为循环读取到并包括您识别的行,而文件中的其余行可以从f 读取。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-22
            • 1970-01-01
            • 1970-01-01
            • 2021-05-30
            • 1970-01-01
            • 2014-12-16
            • 2018-10-12
            • 1970-01-01
            相关资源
            最近更新 更多