我试图从大型非结构化文本文件(每个文件从1,000到15,000行)中提取数据元素,但没有一致的分隔符。数据元素的顺序是一致的。
Sample data:
NAME FIRSTNAME LASTNAME DATE-OF-BIRTH 01/01/2019 ID-NUMBER 123
ADDRESS-1 1234 FAKE STREET COUNTY-CODE 123
ADDRESS-2
CITY NOWHERE STATE OH ZIP 12345
RANDOM DATA .... 700+ LINES
NAME FIRSTNAME2 LASTNAME2 DATE-OF-BIRTH 01/01/2019 ID-NUMBER 4567
ADDRESS-1 123456 OTHER STREET COUNTY-CODE 45678
ADDRESS-2
CITY SOMEWHERE STATE MI ZIP 65432
RANDOM DATA .... 700+ LINES我正在寻找一种使用以下几个字段的值创建CSV输出的方法:
NAME, COUNTY-CODE, ZIP
FIRSTNAME LASTNAME, 123, 12345
FIRSTNAME2 LASTNAME2, 45678, 65432 数据没有制表符分隔,间距也会变化。任何帮助都将不胜感激!
发布于 2019-01-18 11:26:49
嗯..。
我假设您有很多行,每一行包含对ID VALUE,每个块以id NAME开头。
因此,我将使用re模块来搜索预期的模式,名称的出现启动了一个新元素。因为真实的名字和姓氏可以使用多个单词(约翰·菲茨杰拉德·肯尼迪),所以我会把这个名字当作名字和出生日期之间的一切。
IMHO一种简单的方法是在解析行时构建dict,并在到达名称和文件末尾时使用DictWriter编写dict。如果找到更多的关键字,我只会保留每个关键字的第一次出现,但是您也可以引发异常。
代码可能是
import re
import csv
# prepare the patterns to search for
name = re.compile(r"NAME\s+(.*)\s+DATE")
zip_code = re.compile(r"ZIP\s*([0-9]+)")
county_code = re.compile(r"COUNTY-CODE\s*([0-9]+)")
with open("input.txt") as fdin, open("output.csv", newline='') as fdout:
wr = csv.DictWriter(fdout, fieldnames=['NAME', 'COUNTY-CODE', 'ZIP'])
elt = {}
wr.writeheader()
for line in fdin:
# process NAME
mx = name.search(line)
if mx:
if elt: # write previous dict if any
wr.writerow(elt)
elt = {'NAME': mx.group(1).strip()} # initialize a new dict
# process other keywords
if not 'COUNTY-CODE' in elt: # only keep first one
mx = county_code.search(line)
if mx:
elt['COUNTY-CODE'] = mx.group(1).strip() # update the dict with it
if not 'ZIP' in elt:
mx = zip_code.search(line)
if mx:
elt['ZIP'] = mx.group(1)
wr.writerow(elt) # don't forget last dict发布于 2019-01-18 10:09:02
这个问题与发现的在另一个问题上非常相似。
解决方法是构造部分语法,它解析已识别构造的结构,同时跳过无法识别的结构。
在您的例子中,使用textX,这将是一些类似的东西(我还没有测试它,但您得到了图片):
from textx import metamodel_from_str
mm = metamodel_from_str(r'''
File: ( /(?s:.*?(?=NAME))/ persons*=Person | 'NAME' )*
/(?s).*/;
Person:
'NAME' first_name=Name last_name=Name birth_date=Date
'ADDRESS-1' address_1=UntilEOL
'ADDRESS-2' address_2=UntilEOL
'CITY' city=UntilEOL
;
Name: /\w+/;
Date: /\d{4}-\d{2}-\d{2}/;
UntilEOL[noskipws]: /.*?\n/;
''')
data_model = mm.model_from_file('some_input_file.txt')
# Here data_model is an object with attribute `persons`
# where each person have attributes `first_name`, `last_name`, ...
# from the `Person` rule above.注意:这个解决方案假定结构部件的开头必须有关键字NAME,但是可以在随机数据中找到关键字,因为对于规则Person的无效解析,解析器将使用单词NAME并继续。
根据实际数据,您必须稍微调优语法(例如,特定的正则表达式)。
https://stackoverflow.com/questions/54245087
复制相似问题