【问题标题】:Extract data between two lines from text file从文本文件中提取两行之间的数据
【发布时间】:2021-04-17 01:50:50
【问题描述】:

假设我有数百个类似这个例子的文本文件:

NAME
John Doe

DATE OF BIRTH

1992-02-16

BIO 

THIS is
 a PRETTY
 long sentence

 without ANY structure 

HOBBIES 
//..etc..

姓名、出生日期、生物和爱好(以及其他)始终存在,但文本内容和它们之间的行数有时会发生变化。

我想遍历文件并将字符串存储在每个键之间。例如,名为 Name 的变量应包含存储在 'NAME' 和 'DATE OF BIRTH' 之间的值。

这是我发现的:

lines = f.readlines()
for line_number, line in enumerate(lines):
    if "NAME" in line:     
        name = lines[line_number + 1]  # In all files, Name is one line long.
    elif "DATE OF BIRTH" in line:
        date = lines[line_number + 2] # Date is also always two lines after
    elif "BIO" in line:
        for x in range(line_number + 1, line_number + 20): # Length of other data can be randomly bigger
            if "HOBBIES" not in lines[x]:
                bio += lines[x]
            else:
                break
    elif "HOBBIES" in line:
        #...

这很好用,但我觉得与其使用许多双循环,不如用一种更聪明、更简单的方法来做到这一点。

我正在寻找一个通用的解决方案,其中 NAME 将存储所有内容,直到出生日期,而 BIO 将存储所有内容,直到 HOBBIES 等。目的是稍后清理和删除多余的白色棉绒。

有可能吗?

编辑:当我阅读答案时,我意识到我忘记了一个非常重要的细节,键有时会重复(以相同的顺序)。

也就是说,一个文本文件可以包含多个人。应创建人员列表。关键名称标志着一个新人的开始。

【问题讨论】:

  • 您熟悉状态机的概念吗?如果没有,请尝试查找它,看看您是否可以想出一种方法将这个原则应用到您的代码中。
  • 您也可以使用模式来获取特定匹配项ideone.com/PG2sQQ

标签: python algorithm logic extract text-extraction


【解决方案1】:

我将所有内容存储在字典中,请参见下面的代码。

f = open("test.txt")
lines = f.readlines()
dict_text = {"NAME":[], "DATEOFBIRTH":[], "BIO":[]}
for line_number, line in enumerate(lines):
    if not ("NAME" in line or "DATE OF BIRTH" in line or "BIO" in line):
        text = line.replace("\n","")
        dict_text[location].append(text)
    else:
        location = "".join((line.split()))

【讨论】:

    【解决方案2】:

    你可以使用正则表达式:

    import re
    
    keys = """
    NAME
    DATE OF BIRTH
    BIO 
    HOBBIES 
    """.strip().splitlines()
    
    key_pattern = '|'.join(f'{key.strip()}' for key in keys)
    pattern = re.compile(fr'^({key_pattern})', re.M)
    
    # uncomment to see the pattern
    # print(pattern)
    
    with open(filename) as f:
        text = f.read()
        parts = pattern.split(text)
    
    ... process parts ...
    

    parts 将是一个列表字符串。奇数索引位置(parts[1]parts[3]、...)将是键('NAME' 等),偶数索引位置(parts[2]parts[4]、...)将是文本在键之间。 parts[0] 将是第一个键之前的任何内容。

    【讨论】:

      【解决方案3】:

      您可以将文件转换为一个长字符串,而不是读取行。使用 string.index() 查找触发词的起始索引,然后将从该索引到下一个触发词索引的所有内容设置为变量。

      类似:

      string = str(f)
      important_words = ['NAME', 'DATE OF BIRTH']
      last_phrase = None
      for phrase in important_words:
         phrase_start = string.index(phrase)
         phrase_end = phrase_start + len(phrase)
         if last_phrase is not None:
            get_data(string, last_phrase, phrase_start)
         last_phrase = phrase_end
      
      def get_data(string, previous_end_index, current_start_index):
         usable_data = string[previous_end_index: current_start_index]
         return usable_data
      

      应该使用更好/更短的变量名

      【讨论】:

        【解决方案4】:

        您可以将文本读取为 1 个长字符串。然后使用 .split() 这仅在类别有序且不重复时才有效。 像这样;

        Categories = ["NAME", "DOB", "BIO"] // in the order they appear in text
        Output = {}
        Text = str(f)
        for i in range(1,len(Categories)):
            SplitText = Text.split(Categories[i])
            Output.update({Categories[i-1] : SplitText[0] })
            Text = SplitText[1]
        Output.update({Categories[-1] : Text}) 
        

        【讨论】:

          【解决方案5】:

          您可以尝试以下方法。

          keys = ["NAME","DATE OF BIRTH","BIO","HOBBIES"]
          
          f = open("data.txt", "r")
          result = {}
          for line in f:
              line = line.strip('\n')
              if any(v in line for v in keys):
                  last_key = line
              else:
                  result[last_key] = result.get(last_key, "") + line
          
          print(result)
          

          输出

          {'NAME': 'John Doe', 'DATE OF BIRTH': '1992-02-16', 'BIO ': 'THIS is a PRETTY long sentence without ANY structure ', 'HOBBIES ': '//..etc..'}
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-11
            • 1970-01-01
            相关资源
            最近更新 更多