从文本文件中提取两行之间的数据
Extract data between two lines from text file
假设我有数百个这样的文本文件:
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 等。目的是稍后清理和删除多余的白色棉绒。
可能吗?
编辑 : 当我阅读答案时,我意识到我忘记了一个非常重要的细节,键有时会重复(以相同的顺序)。
也就是说,一个文本文件可以包含一个以上的人。应创建人员名单。键名表示新人的开始。
我将所有内容存储在字典中,请参阅下面的代码。
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()))
您可以使用正则表达式:
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]
将是第一个键之前的任何内容。
您可以尝试以下方法。
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..'}
您可以将文件转换为一个长字符串,而不是读取行。使用 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
Better/shorter 可能应该使用变量名
您可以只读取 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})
假设我有数百个这样的文本文件:
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 等。目的是稍后清理和删除多余的白色棉绒。
可能吗?
编辑 : 当我阅读答案时,我意识到我忘记了一个非常重要的细节,键有时会重复(以相同的顺序)。
也就是说,一个文本文件可以包含一个以上的人。应创建人员名单。键名表示新人的开始。
我将所有内容存储在字典中,请参阅下面的代码。
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()))
您可以使用正则表达式:
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]
将是第一个键之前的任何内容。
您可以尝试以下方法。
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..'}
您可以将文件转换为一个长字符串,而不是读取行。使用 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
Better/shorter 可能应该使用变量名
您可以只读取 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})