我在将文本文件解析为字典时遇到问题

时间:2012-08-09 22:47:18

标签: python

我有一个文本文件,我想将它加载到Python中的字典中。

文本看起来像这样,制表符分隔:

  

Form Dosage ReferenceDrug drugname activeingred   注射用;注射20,000单位/ ML LIQUAEMIN SODIUM HEPARIN SODIUM   注射用;注射40,000单位/ ML LIQUAEMIN SODIUM HEPARIN SODIUM   注射用;注射5,000单位/ ML LIQUAEMIN SODIUM HEPARIN SODIUM

现在我的代码看起来像这样,但它不起作用(列表索引超出范围,没有任何东西被推送到字典)。我不知道我哪里出错了,不知道程序员。谢谢你的帮助。

import sys

def load_medications(filename):
    meds_dict = {}
    f = open(filename)
    l = " "
    # print f.read()
    for line in f:
        fields = l.split("\t")
        ApplNo = fields[0]
        ProductNo = fields[1]
        Form = fields[2]
        Dosage = fields[3]
        ProductMktStatus = fields[4]
        TECode = fields[5]
        ReferenceDrug = fields[6]
            DrugName = fields[7]
        ActiveIngred = fields[8]

        meds = {
                "ApplNo": ApplNo,   
                "ProductNo": ProductNo, 
                "Form": Form,
                "Dosage": Dosage,   
                "ProductMktStatus": ProductMktStatus,
                "TECode": TECode,
                "ReferenceDrug": ReferenceDrug, 
                "DrugName": DrugName,
                "ActiveIngred": ActiveIngred
            }       
        meds_dict[DrugName] = meds
    f.close()
    return meds_dict


def main():
    x = load_medications("druglist.txt")
    print x



if __name__ == "__main__":
    main()

7 个答案:

答案 0 :(得分:2)

试试line.split而不是l.split

答案 1 :(得分:2)

您可以更轻松地使用the CSV module in the standard library解析此数据 - 如果您使用制表符作为分隔符并将;作为行终止符进行装配,则解析您发布的文件时应该没有任何问题

使用DictReader也可以让您更轻松地阅读行(您可以将内容称为line['ApplNo']而不是line[0])。

不幸的是,它看起来不像你文件中的标题映射到你想在代码中调用它们的那些 - 所以你需要根据字典中的内容自己分配字段的名称。

答案 2 :(得分:1)

您应该查看csv.DictReader,假设您的文件在开头有一个正确的标题行,您应该可以像这样简单地创建您的词典:

def load_medications(filename):
    reader = csv.DictReader(open(filename), delimiter='\t')
    meds = {}
    for row in reader:
        meds[row['DrugName']] = row
    return meds

如果您的文件没有标题行,则可以将字段名称传递给DictReader初始化程序:

fields = ["ApplNo", "ProductNo", "Form", "Dosage", "ProductMktStatus"
          "TECode", "ReferenceDrug", "DrugName", "ActiveIngred"]
reader = csv.DictReader(open(filename), delimiter='\t', fieldnames=fields)

答案 3 :(得分:0)

我认为你高估了文件的列数。 ApplNoProductNo在哪里?

答案 4 :(得分:0)

您实际上拆分了l,而不是line。你想要:

def load_medications(filename):
    meds_dict = {}
    with open(filename) as f: # Ensure that the file gets closed
        for line in f:
            fields = line.split("\t") # line, not l
            keys = ["ApplNo", "ProductNo", "Form", "Dosage", "ProductMktStatus",
                    "TECode", "ReferenceDrug", "DrugName", "ActiveIngred",]

            if len(fields) != len(keys):
                raise ValueError("Malformed input line " + repr(line))

            meds = dict(zip(keys, fields))
            meds_dict[meds["DrugName"]] = meds
    return meds_dict

有关其原因的详细信息,请阅读zipdict

答案 5 :(得分:0)

看起来您的代码假定特定药物有9种属性。您发布的示例文本文件只有5个属性。当您调用fields = l.split("\t")时,将返回仅包含5个元素的数组,因为“druglist.txt”中只有5个元素。因此,如果您使用大于或等于5的值(即fields)索引fields[8],您将获得“索引超出范围”异常。

答案 6 :(得分:0)

由于您的字段名称都是有效的Python标识符,为什么不将您的数据读入namedtuples而不是dicts?

data = """Form Dosage ReferenceDrug drugname activeingred INJECTABLE; INJECTION 20,000 UNITS/ML LIQUAEMIN   SODIUM HEPARIN  SODIUM  INJECTABLE; INJECTION   40,000 UNITS/ML LIQUAEMIN   SODIUM HEPARIN  SODIUM  INJECTABLE; INJECTION   5,000 UNITS/ML  LIQUAEMIN   SODIUM HEPARIN  SODIUM  INJECTABLE""".split('; ')

from collections import namedtuple

# define class DrugData as a namedtuple, using the headers from data[0]
DrugData = namedtuple("DrugData", data[0])

# use a list comprehension to create a DrugData for each data line
druglist = [DrugData(*line.split('\t')) for line in data[1:]]

# access each tuple in druglist, using attribute access to individual fields
for d in druglist:
    print "%s | %s | %s" % (d.ReferenceDrug, d.Form, d.Dosage)

打印:

LIQUAEMIN | INJECTION | 20,000 UNITS/ML
LIQUAEMIN | INJECTION | 40,000 UNITS/ML
LIQUAEMIN | INJECTION | 5,000 UNITS/ML

编辑:

回顾原始问题,看起来您想要创建所有这些条目的单个字典,由drugname键入。不幸的是,dict键必须是唯一的,在您的示例中,所有3个条目都具有相同的drugname。您可能必须组合2个或更多字段才能为处理所有这些值的字典组成一个真正唯一的键,例如(drugname, Dosage)的元组。

或者,稍微更改您的设计,以便每个drugname指向匹配值的列表。最简单的方法是使用defaultdict而不是dict,以便使用空列表自动初始化新条目。在您的代码中,您将添加一个import语句:

from collections import defaultdict

并将meds_dict的声明更改为:

meds_dict = defaultdict(list)

意味着任何尚未见过的新密钥都将使用作为defaultdict参数提供的函数/类进行初始化,在本例中为list

然后要向meds_dict添加新条目,而不是使用'='分配,您将附加到所有匹配的meds /剂量列表中:

meds_dict[DrugName].append(meds)

现在对于任何DrugName,您将获得匹配表格/剂量/等的列表。记录。