如何将文本文件中的值解析为列表,同时用 None 填充缺失值?
How to parse values from a text file into a list, while filling missing values with None?
- 我有一个正在解析的原始数据的文本文件。
- 其中有一些代码指示该字段。
- 这些值将进入列表,然后进入 pandas 中的数据框,最终进入数据库
例如,有 2 条记录的一小部分如下所示:
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*690553677~
DTP*348*D8*20200601~
DTP*349*D8*20200630~
HD*024**FAC*KJ/165/////1M*IND~
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*6905456455~
DTP*348*D8*20200601~
HD*024**FAC*KJ/165/////1M*IND~
- "DTP"表示日期,348表示
start_date
,349表示end_date
。
- 每组行对应会员数据中的一个会员。
- “REF”是会员编号所在的行。
- “INS”表示它是数据库中的新成员或记录。
- 有些成员没有像我们的第二条记录那样的
end_date
行 "DTP*349"。
- 这些应该附加到
end_date
列表中,并用“”作为空值保留一个位置
- 在遍历每一行的同时,寻找该行以我想要的代码开始的位置,并拆分该行,并获取指定的元素。
- 我如何解释循环中缺少某个字段的位置,以便无论成员是否具有
end_date
,该成员索引位置都会有一个值, 所以它都可以放在一个 pandas 数据框中?
到目前为止,我的代码如下所示:
membership_type=[]
member_id=[]
startDate = []
endDate = []
with open(path2 + fileName, "r") as txtfile:
for line in txtfile:
# Member type
if line.startswith("INS*"):
line.split("*")
membership_type.extend(line[4]
# Member ID
if line.startwith("REF*"):
line.split("*")
member_id.extend(line[2])
# Start Dates
if line.startswith("DTP*348*"):
line = line.split("*")
start_date.extend(line[3])
# End Dates
'''What goes here?'''
结果应如下所示:
print(membership_type)
['AL','AL']
print(member_id)
['690553677','690545645']
print(startDate)
['20200601','20200601']
print(endDate)
['20200630','']
- 每个记录将有一个
INS
和REF
和HD
字段
- 使用
readlines
获取字符串的所有行
- 清理文本行,然后使用
re.split
拆分多个项目,在本例中为 *
和 /
。
- 拆分
/
将正确分隔字符串中的唯一项,但也会创建要删除的空格。
- 每行使用
enumerate
- 在整个行列表中,您可以看到当前索引,
i
,但是 i
+ 或 - 数字也可用于比较不同的行。
- 如果 DTP 348 之后的下一行不是 DTP,则添加
None
或 ''
。
- 用
None
填空以方便在pandas中转换为datetime
格式。
- 请记住,
line
是 lines
中的一行,其中每个 line
是 enumerated
和 i
。当前的line
是lines[i]
,下一个line
是lines[i + 1]
。
import re
membership_type = list()
member_id = list()
start_date = list()
end_date = list()
name = list()
first_name = list()
middle_name = list()
last_name = list()
with open('test.txt', "r") as f:
lines = [re.split('\*|/', x.strip().replace('~', '')) for x in f.readlines()] # clean and split each row
lines = [[i for i in l if i] for l in lines] # remove blank spaces
for i, line in enumerate(lines):
print(line) # only if you want to see
# Member type
if line[0] == "INS":
membership_type.append(line[4])
# Member ID
elif line[0] == 'REF':
member_id.append(line[2])
# Start Dates
elif (line[0] == 'DTP') and (line[1] == '348'):
start_date.append(line[3])
if (lines[i + 1][0] != 'DTP'): # the next line should be the end_date, if it's not, add None
end_date.append(None)
# End Dates
elif (line[0] == 'DTP') and (line[1] == '349'):
end_date.append(line[3])
# Names
elif line[0] == 'NM1':
name.append(' '.join(line[3:]))
first_name.append(line[3])
middle_name.append(line[4])
last_name.append(line[5])
try:
some_list.append(line[6])
except IndexError:
print('No prefix')
some_list.append(None)
try:
some_list.append(line[7])
except IndexError:
print('No suffix')
some_list.append(None)
print(membership_type)
print(member_id)
print(start_date)
print(end_date)
print(name)
print(first_name)
print(middle_name)
print(last_name)
['AL', 'AL']
['690553677', '6905456455']
['20200601', '20200601']
['20200630', None]
['SMITH JOHN PAUL MR JR', 'IMA MEAN TURD MR SR']
['SMITH', 'IMA']
['JOHN', 'MEAN']
['PAUL', 'TURD']
加载到pandas
import pandas as pd
data = {'start_date': start_date , 'end_date': end_date, 'member_id': member_id, 'membership_type': membership_type,
'name': name, 'first_name': first_name, 'middle_name': middle_name, 'last_name': last_name}
df = pd.DataFrame(data)
# convert datetime columns
df.start_date = pd.to_datetime(df.start_date)
df.end_date = pd.to_datetime(df.end_date)
# display df
start_date end_date member_id membership_type name first_name middle_name last_name
0 2020-06-01 2020-06-30 690553677 AL SMITH JOHN PAUL MR JR SMITH JOHN PAUL
1 2020-06-01 NaT 6905456455 AL IMA MEAN TURD MR SR IMA MEAN TURD
test.txt
的内容
NM1*IL*1*SMITH*JOHN*PAUL*MR*JR~
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*690553677~
DTP*348*D8*20200601~
DTP*349*D8*20200630~
HD*024**FAC*KJ/165/////1M*IND~
NM1*IL*1*IMA*MEAN*TURD*MR*SR~
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*6905456455~
DTP*348*D8*20200601~
HD*024**FAC*KJ/165/////1M*IND~
- 我有一个正在解析的原始数据的文本文件。
- 其中有一些代码指示该字段。
- 这些值将进入列表,然后进入 pandas 中的数据框,最终进入数据库
例如,有 2 条记录的一小部分如下所示:
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*690553677~
DTP*348*D8*20200601~
DTP*349*D8*20200630~
HD*024**FAC*KJ/165/////1M*IND~
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*6905456455~
DTP*348*D8*20200601~
HD*024**FAC*KJ/165/////1M*IND~
- "DTP"表示日期,348表示
start_date
,349表示end_date
。 - 每组行对应会员数据中的一个会员。
- “REF”是会员编号所在的行。
- “INS”表示它是数据库中的新成员或记录。
- 有些成员没有像我们的第二条记录那样的
end_date
行 "DTP*349"。- 这些应该附加到
end_date
列表中,并用“”作为空值保留一个位置
- 这些应该附加到
- 在遍历每一行的同时,寻找该行以我想要的代码开始的位置,并拆分该行,并获取指定的元素。
- 我如何解释循环中缺少某个字段的位置,以便无论成员是否具有
end_date
,该成员索引位置都会有一个值, 所以它都可以放在一个 pandas 数据框中?
到目前为止,我的代码如下所示:
membership_type=[]
member_id=[]
startDate = []
endDate = []
with open(path2 + fileName, "r") as txtfile:
for line in txtfile:
# Member type
if line.startswith("INS*"):
line.split("*")
membership_type.extend(line[4]
# Member ID
if line.startwith("REF*"):
line.split("*")
member_id.extend(line[2])
# Start Dates
if line.startswith("DTP*348*"):
line = line.split("*")
start_date.extend(line[3])
# End Dates
'''What goes here?'''
结果应如下所示:
print(membership_type)
['AL','AL']
print(member_id)
['690553677','690545645']
print(startDate)
['20200601','20200601']
print(endDate)
['20200630','']
- 每个记录将有一个
INS
和REF
和HD
字段
- 使用
readlines
获取字符串的所有行- 清理文本行,然后使用
re.split
拆分多个项目,在本例中为*
和/
。 - 拆分
/
将正确分隔字符串中的唯一项,但也会创建要删除的空格。 - 每行使用
enumerate
- 在整个行列表中,您可以看到当前索引,
i
,但是i
+ 或 - 数字也可用于比较不同的行。 - 如果 DTP 348 之后的下一行不是 DTP,则添加
None
或''
。- 用
None
填空以方便在pandas中转换为datetime
格式。
- 用
- 请记住,
line
是lines
中的一行,其中每个line
是enumerated
和i
。当前的line
是lines[i]
,下一个line
是lines[i + 1]
。
- 在整个行列表中,您可以看到当前索引,
- 清理文本行,然后使用
import re
membership_type = list()
member_id = list()
start_date = list()
end_date = list()
name = list()
first_name = list()
middle_name = list()
last_name = list()
with open('test.txt', "r") as f:
lines = [re.split('\*|/', x.strip().replace('~', '')) for x in f.readlines()] # clean and split each row
lines = [[i for i in l if i] for l in lines] # remove blank spaces
for i, line in enumerate(lines):
print(line) # only if you want to see
# Member type
if line[0] == "INS":
membership_type.append(line[4])
# Member ID
elif line[0] == 'REF':
member_id.append(line[2])
# Start Dates
elif (line[0] == 'DTP') and (line[1] == '348'):
start_date.append(line[3])
if (lines[i + 1][0] != 'DTP'): # the next line should be the end_date, if it's not, add None
end_date.append(None)
# End Dates
elif (line[0] == 'DTP') and (line[1] == '349'):
end_date.append(line[3])
# Names
elif line[0] == 'NM1':
name.append(' '.join(line[3:]))
first_name.append(line[3])
middle_name.append(line[4])
last_name.append(line[5])
try:
some_list.append(line[6])
except IndexError:
print('No prefix')
some_list.append(None)
try:
some_list.append(line[7])
except IndexError:
print('No suffix')
some_list.append(None)
print(membership_type)
print(member_id)
print(start_date)
print(end_date)
print(name)
print(first_name)
print(middle_name)
print(last_name)
['AL', 'AL']
['690553677', '6905456455']
['20200601', '20200601']
['20200630', None]
['SMITH JOHN PAUL MR JR', 'IMA MEAN TURD MR SR']
['SMITH', 'IMA']
['JOHN', 'MEAN']
['PAUL', 'TURD']
加载到pandas
import pandas as pd
data = {'start_date': start_date , 'end_date': end_date, 'member_id': member_id, 'membership_type': membership_type,
'name': name, 'first_name': first_name, 'middle_name': middle_name, 'last_name': last_name}
df = pd.DataFrame(data)
# convert datetime columns
df.start_date = pd.to_datetime(df.start_date)
df.end_date = pd.to_datetime(df.end_date)
# display df
start_date end_date member_id membership_type name first_name middle_name last_name
0 2020-06-01 2020-06-30 690553677 AL SMITH JOHN PAUL MR JR SMITH JOHN PAUL
1 2020-06-01 NaT 6905456455 AL IMA MEAN TURD MR SR IMA MEAN TURD
test.txt
的内容
NM1*IL*1*SMITH*JOHN*PAUL*MR*JR~
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*690553677~
DTP*348*D8*20200601~
DTP*349*D8*20200630~
HD*024**FAC*KJ/165/////1M*IND~
NM1*IL*1*IMA*MEAN*TURD*MR*SR~
INS*Y*18*001*AL*A*E**AC**N~
REF*1L*6905456455~
DTP*348*D8*20200601~
HD*024**FAC*KJ/165/////1M*IND~