【问题标题】:parse blocks of text from text file using Python使用 Python 从文本文件中解析文本块
【发布时间】:2014-07-30 21:25:09
【问题描述】:

我正在尝试解析一些文本文件并需要提取文本块。具体来说,以“1:”开头的行和文本后的 19 行。 “1:”不在每个文件的同一行开始,并且只有一个“1:”实例。我更愿意保存文本块并将其导出到单独的文件中。另外,我需要保留原文件中文本的格式。

不用说我是 Python 新手。我通常使用 R,但这些文件与 R 并不真正兼容,我有大约 100 个要处理。任何信息,将不胜感激。

我目前的代码是:

tmp = open(files[0],"r") 
lines = tmp.readlines()
tmp.close()

num = 0
a=0

for line in lines:
    num += 1    
    if "1:" in line:
      a = num 
      break

a = num 是我想要的文本块的行号。然后我想将接下来的 19 行代码保存到另一个文件中,但不知道如何执行此操作。任何帮助将不胜感激。

【问题讨论】:

  • 如果您只需要提取这些行,您无需编写全新的程序即可:egrep -A 19 "^1:" myfile.txt
  • 这行得通,但我得写一个批处理文件来处理所有文件,对吧?
  • 也许,也许不是。我对你的情况没有足够的了解。
  • 输入文件有多大,通常和最大?
  • 附议@Robᵩ,没有理由为此使用python。如果你愿意,你可以在 python 中为 grep 编写一个包装器,但这对 grep 来说是个问题。

标签: python string-parsing


【解决方案1】:

这是一种选择。从文件中读取所有行。迭代直到你找到你的行并返回接下来的 19 行。您需要处理文件不包含额外 19 行的情况。

    fh = open('yourfile.txt', 'r')
    all_lines = fh.readlines()
    fh.close()
    for count, line in enumerate(all_lines):
        if "1:" in line:
            return all_lines[count+1:count+20]

【讨论】:

  • 嗨,这可能很好地解决了这个问题......但如果你能提供一些关于它如何工作以及为什么工作的解释会很好:) 不要忘记 - 有很多新手在 Stack Overflow 上,他们可以从你的专业知识中学到一两件事——对你来说显而易见的事情对他们来说可能并不那么明显。
  • 添加了一些文字。这是我在这里的第一篇文章,似乎有一些热情的选民!
  • 是的,为了让人们了解一个好的(或不好的)答案是什么样的,我们鼓励它投反对票 :) 这不是个人的......尽管人们真的应该就为什么发表评论,并且仅代码的答案经常被否决(顺便说一句,我没有投反对票);)
  • 我也喜欢这个解决方案,但由于某种原因我无法回到这里工作。当我用 print 替换 return 时它会起作用。
【解决方案2】:

可以单线完成...

open(files[0]).read().split('1:', 1)[1].split('\n')[:19]

或更具可读性

txt = open(files[0]).read()           # read the file into a big string
before, after = txt.split('1:', 1)    # split the file on the first "1:"
after_lines = after.split('\n')       # create lines from the after text
lines_to_save = after_lines[:19]      # grab the first 19 lines after "1:"

然后在写入新文件之前用换行符连接行(并在末尾添加换行符):

out_text = "1:"                       # add back "1:"
out_text += "\n".join(lines_to_save)  # add all 19 lines with newlines between them
out_text += "\n"                      # add a newline at the end

open("outputfile.txt", "w").write(out_text)

为了遵守读写文件的最佳实践,您还应该使用 with 语句来确保尽快关闭文件句柄。你可以为它创建方便的函数:

def read_file(fname):
    "Returns contents of file with name `fname`."
    with open(fname) as fp:
         return fp.read()

def write_file(fname, txt):
    "Writes `txt` to a file named `fname`."
    with open(fname, 'w') as fp:
         fp.write(txt)

那么您可以将上面的第一行替换为:

txt = read_file(files[0])

最后一行是:

write_file("outputfile.txt", out_text)

【讨论】:

  • thebjorn,我喜欢这个解决方案,因为我可以理解代码,但是如何在输出文件中保留“1:”?另外,原始文件的格式丢失了,所以我认为最好逐行阅读。
  • 您必须手动添加 1:,因为 split 会删除它。您可以打印afterafter_lineslines_to_save 以查看发生了什么。
  • ps:我不确定我是否理解丢失的格式 -- split('\n')"\n".join(..) 应该保持文件原样..?
  • 对于我所做的工作来说,这非常有效,因为它以原始文本文件的格式保存了数据。
【解决方案3】:

我总是喜欢先将文件读入内存,但有时这是不可能的。如果您想使用迭代,那么这将起作用:

def process_file(fname):
    with open(fname) as fp:
        for line in fp:
            if line.startswith('1:'):
                break
        else:
            return    # no '1:' in file

        yield line    # yield line containing '1:'
        for i, line in enumerate(fp):
            if i >= 19:
                break
            yield line


if __name__ == "__main__":
    with open('ouput.txt', 'w') as fp:
        for line in process_file('intxt.txt'):
            fp.write(line)

它在 for 循环中使用了 else: 子句,您不再经常看到它,但它只是为了这个目的而创建的(如果 for 循环没有中断,则执行 else 子句)。

【讨论】: