Python从d行中提取并重新格式化字段名

2024-10-06 07:41:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个平面文本文件(内嵌),我想重组。它有几个制表符分隔的列,如下所示:

 Person1    HEIGHT=60;WEIGHT=100;AGE=22
 Person2    HEIGHT=62;WEIGHT=101;AGE=25
 Person3    HEIGHT=64;WEIGHT=110;AGE=29

我希望它看起来像这样:

^{pr2}$

您可以看到第二列实际上包含几个以分号分隔的头/值字段,我希望将它们重新构造为典型的列标题行。在

现在我有:

for line in infile:
        line = line.split("\t")
        line_meta = line[1].split(";")
        print line_meta

我认为最好的解决方案是现在循环使用meta变量,使用正则表达式检测头名称(检测以多个大写字母开头、以“=”结尾的字符串),将每个标头作为键添加到字典中,然后将字符串的其余部分存储为值。然后,对于下一行,如果检测到相同的头,只需将其附加到现有字典中。在

有人能帮助使用这个代码或提供关于如何继续的反馈吗?在

谢谢你

编辑:感谢您的回复。我简化了本例中的数据,但下面是一个实际的meta列(仍然是分隔的,但值类型是混合的):

       P=0.9626;IPU=.$.+1T.+1T.+;IRF=ncRNA;IUC=UTR3;IGN=NCRNA00115;IGI=NCRNA00115,RP11-206L10.16-001;IET=0;IEO=0;IEN=.;IHT=0;IHVC=0;IHD=.;IHI=.;IHN=.;IDI=.;IDN=.;ITMAF=.;ITAMR=.;ITASN=.;ITAFR=.;ITEUR=.;ITNRB=+A;ISF=.;ISD=.;ISM=.;ISX=.;

Tags: 字符串age字典linemeta制表符平面split
2条回答

你可以试试这个

data = open('testfile.dat').read().split('\n')

def newcmp(x,y): 
    rv = cmp(len(x[1]), len(y[1]))
    if rv: return rv
    else: return cmp(x[0], y[0]) # alphabetical 

persons = {}
attributes = {}
nAttrs = 0
for l in data:
    pname , pvals = line.split('\t')[:2]
    for atName, atVal in (x.split('=') for x in pvals.psplit(';'))
        try:
            persons[pName][attributes[atName]] = atVal
        except KeyError:
            attributes[aName] = nAttrs
            persons[pName][attributes[atName]] = atVal
            nAttr += 1

headers = ['NAME'] + range(nAttrs)
for x in attributes.keys(): headers[attributes[x]+1] = x
values = []
for pName, pVals in sorted(persons.items(), cmp=newcmp)
    if len(pVals) < nAttrs: pVals += [0 for x in xrange(nAttrs - len(pVals))]
    values.append('\t'.join(('%d'%x for x in pVals)))

outfh = open('outputfile.dat', 'w')
outfh.write('%s\n%s\n'%('\t'.join(headers), '\n'.join(values)))
outfh.close()

您只需使用一个正则表达式来拆分key=value对:

import re

key_value = re.compile('(?P<key>[A-Z]+)=(?P<value>\[^\s=;]+)(?:(?=;)|$)')

此表达式使用命名组,但如果您觉得更易于阅读,则可以不使用这些组:

^{pr2}$

(?:..)组是一个非捕获组;它仅用于标记|或符号应用于什么。该模式匹配=符号之前的大写字符,以及任何空白、=;字符,前提是在值后面有一个;。在

这将为每行拆分键和值:

>>> key_value = re.compile('(?P<key>[A-Z]+)=(?P<value>[^\s=;]+)(?:(?=;)|$)')
>>> key_value.findall('Person1\tHEIGHT=60;WEIGHT=100;AGE=22')
[('HEIGHT', '60'), ('WEIGHT', '100'), ('AGE', '22')]

这很容易就可以变成字典:

>>> dict(key_value.findall('Person1\tHEIGHT=60;WEIGHT=100;AGE=22'))
{'AGE': '22', 'WEIGHT': '100', 'HEIGHT': '60'}

然后可以使用^{}编写这些内容:

import csv
import re

key_value = re.compile('(?P<key>[A-Z]+)=(?P<value>[^\s=;]+)(?:(?=;)|$)')

with open(inputfilename) as infile, open(outputfilename, 'wb') as outfile:
    writer = csv.DictWriter(outfile, ('PERSON', 'HEIGHT', 'WEIGHT', 'AGE'), delimiter='\t')
    writer.writeheader()

    for line in infile:
        person = line.split('\t', 1)[0]
        row = dict(key_value.findall(line))
        row['PERSON'] = person
        writer.writerow(row)

基于真实数据示例的演示:

>>> dict(key_value.findall('       P=0.9626;IPU=.$.+1T.+1T.+;IRF=ncRNA;IUC=UTR3;IGN=NCRNA00115;IGI=NCRNA00115,RP11-206L10.16-001;IET=0;IEO=0;IEN=.;IHT=0;IHVC=0;IHD=.;IHI=.;IHN=.;IDI=.;IDN=.;ITMAF=.;ITAMR=.;ITASN=.;ITAFR=.;ITEUR=.;ITNRB=+A;ISF=.;ISD=.;ISM=.;ISX=.;\n'))
{'ISX': '.', 'ITAMR': '.', 'IDN': '.', 'ISM': '.', 'IDI': '.', 'ISF': '.', 'ISD': '.', 'ITMAF': '.', 'IUC': 'UTR3', 'IGI': 'NCRNA00115,RP11-206L10.16-001', 'ITNRB': '+A', 'IHVC': '0', 'IET': '0', 'ITASN': '.', 'ITEUR': '.', 'ITAFR': '.', 'IEO': '0', 'IEN': '.', 'IGN': 'NCRNA00115', 'IRF': 'ncRNA', 'P': '0.9626', 'IHT': '0', 'IHI': '.', 'IHN': '.', 'IPU': '.$.+1T.+1T.+', 'IHD': '.'}

相关问题 更多 >