使用Python将文本文件转换为CSV
我需要帮助来解析一个非常长的文本文件,内容大概是这样的:
NAME IMP4
DESCRIPTION small nucleolar ribonucleoprotein
CLASS Genetic Information Processing
Translation
Ribosome biogenesis in eukaryotes
DBLINKS NCBI-GI: 15529982
NCBI-GeneID: 92856
OMIM: 612981
///
NAME COMMD9
DESCRIPTION COMM domain containing 9
ORGANISM H.sapiens
DBLINKS NCBI-GI: 156416007
NCBI-GeneID: 29099
OMIM: 612299
///
.....
我想要得到一个结构化的csv文件,每一行的列数都要一样,这样我才能方便地提取我需要的信息。
我最开始是这样尝试的:
for line in a:
if '///' not in line:
b.write(''.join(line.replace('\n', '\t')))
else:
b.write('\n')
结果得到了一个这样的csv文件:
NAME IMP4\tDESCRIPTION small nucleolar ribonucleoprotein\tCLASS Genetic Information Processing\t Translation\t Ribosome biogenesis in eukaryotes\tDBLINKS NCBI-GI: 15529982\t NCBI-GeneID: 92856\t
OMIM: 612981
NAME COMMD9\tDESCRIPTION COMM domain containing 9\tORGANISM H.sapiens\tDBLINKS NCBI-GI: 156416007\t NCBI-GeneID: 29099t\ OMIM: 612299
主要的问题在于,像DBLINKS这样的字段在原始文件中是分成多行的,这样就导致它们被拆分成了多个字段,而我希望它们能合并成一个字段。此外,并不是每一行都有所有字段,比如在这个例子中,'CLASS'和'ORGANISM'字段就没有出现在每一行。
我希望得到的文件应该是这样的:
NAME IMP4\tDESCRIPTION small nucleolar ribonucleoprotein\tNA\tCLASS Genetic Information Processing; Translation; Ribosome biogenesis in eukaryotes\tDBLINKS NCBI-GI: 15529982; NCBI-GeneID: 92856; OMIM: 612981
NAME COMMD9\tDESCRIPTION COMM domain containing 9\tORGANISM H.sapiens\tNA\tDBLINKS NCBI-GI: 156416007; NCBI-GeneID: 29099; OMIM: 612299
你能帮我一下吗?
2 个回答
0
这个脚本可以把你的文本文件转换成一个有效的CSV文件(比如可以用Excel打开的那种):
import sys
from sets import Set
if len(sys.argv) < 2:
print 'Usage: %s <input-file> <output-file>' % sys.argv[0]
sys.exit(1)
entries = []
entry = {}
# Read the input file
with open(sys.argv[1]) as input:
lines = input.readlines()
for line in lines:
# Check for beginning of new entry
if line.strip() == '///':
if len(entry) > 0:
entries.append(entry)
entry = {}
continue
# Check for presense of key
possible_key = line[:13].strip()
if possible_key != '':
key = possible_key
entry[key] = []
# Assemble the value
if key:
entry[key].append(line[13:].strip())
# Append the last entry
if len(entry) > 0:
entries.append(entry)
# 'entries' now contains a list of a dict of a list
# Find out all possible keys
all_keys = Set()
for entry in entries:
all_keys.union_update(entry.keys())
# Write all entries to the output file
with open(sys.argv[2], 'w') as output:
# The first line will contain the keys
output.write(','.join(['"%s"' % key for key in sorted(all_keys)]))
output.write('\r\n')
# Write each entry
for entry in entries:
output.write(','.join(['"%s"' % ';'.join(entry[key]) if key in entry else '' for key in sorted(all_keys)]))
output.write('\r\n')
5
你可以使用 itertools.groupby,第一次用来把多行合并成记录,第二次用来把多行字段收集成一个迭代器:
import csv
import itertools
def is_end_of_record(line):
return line.startswith('///')
class FieldClassifier(object):
def __init__(self):
self.field=''
def __call__(self,row):
if not row[0].isspace():
self.field=row.split(' ',1)[0]
return self.field
fields='NAME DESCRIPTION ORGANISM CLASS DBLINKS'.split()
with open('data','r') as f:
for end_of_record, lines in itertools.groupby(f,is_end_of_record):
if not end_of_record:
classifier=FieldClassifier()
record={}
for fieldname, row in itertools.groupby(lines,classifier):
record[fieldname]='; '.join(r.strip() for r in row)
print('\t'.join(record.get(fieldname,'NA') for fieldname in fields))
这样会产生
NAME IMP4 DESCRIPTION small nucleolar ribonucleoprotein NA CLASS Genetic Information Processing; Translation; Ribosome biogenesis in eukaryotes DBLINKS NCBI-GI: 15529982; NCBI-GeneID: 92856; OMIM: 612981
NAME COMMD9 DESCRIPTION COMM domain containing 9 ORGANISM H.sapiens NA DBLINKS NCBI-GI: 156416007; NCBI-GeneID: 29099; OMIM: 612299
上面的内容就是你看到的输出结果。它和你提供的期望输出是一样的,前提是你展示的是这个输出的 repr
形式。
使用到的工具参考:
- itertools.groupby
- 一个带有
__call__
方法的类 - str.join 和一个 生成器表达式,理解这个之前最好先了解一下 列表推导式
- 带有默认值的 dict.get 方法