将txt文件加载到dict中,不包括注释行,但注释行包含dict键

时间:2014-09-09 00:16:20

标签: python list dictionary

我有非常大的文本文件需要加载到python字典中。文本文件包含许多行,这些行描述所有以“#”开头的数据。我知道如何在将数据读入列表(if not line.startswith('#'))时排除这些行,然后将该列表转换为字典(data_dict = map(lambda row:dict(zip(header,row)),data))。

我遇到的问题是我的代码假定我已经知道标题是什么,并且我可以从文本文件中提取header。这个头文件可以在文件之间稍微改变一下,所以我很难对它进行硬编码,就像我现在所做的那样。此标题行包含在我正在读取文件时跳过的注释字段中。

以下提供了数据样本:

# Date: 9/26/2014
# Time: 12:04 PM
# Source: XYZ Database
# User: green_bean_4_u
# Headers: tweet_type, user_screeenname, user_id, user_language, event_date
reply;tweeterA;10001;en;9/6/2014m
mention;tweeterB;10002;en;9/6/2014m
retweet;tweeterC;10003;ar;9/6/2014m
mention;tweeterC;10003;ar;9/7/2014m
retweet;tweeterA;10001;en;9/8/2014m
reply;tweeterZ;100026;fr;9/30/2014m

我用来将数据读入列表的代码,不包括已注释的行,并使用提供的标题转换为dict:

In [2]: data = []

In [3]: for line in open('text_data.txt', 'rb'):
            if not line.startswith('#'):
                data.append(line.rstrip().split(';'))

In [4]: header = ['tweet_type', 'user_screeenname', 'user_id', 'user_language', 'event_date']

In [5]: data_dict =  map(lambda row:dict(zip(header,row)),data)

In [6]: data_dict[0]
Out[6]: {'event_date': '9/6/2014',
          'type': 'reply',
          'user_id': '10001',
          'user_language': 'en',
          'user_screeenname': 'tweeterA'}

正如我所说,问题在于它假设标题或字典键保持不变,并且不会改变,这是不正确的。我想帮助弄清楚如何从一个注释行中提取密钥以用于将列表压缩成字典。

4 个答案:

答案 0 :(得分:1)

elif添加到读取标题的if语句中:

if not line.startswith('#'):
    data.append(line.rstrip().split(';'))
elif line.startswith("# Headers:")
    # remove the "Headers: " part
    after = line.rstrip().split(": ")[1]
    # split around the commas to create the header list
    header = after.split(", ")

答案 1 :(得分:0)

如果包含标题的行唯一保证以# Headers开头,那么您的代码可能是这样的:

for line in open('text_data.txt', 'rb'):
    if line.startswith('# Headers'):
        header.append(line.rstrip().split(','))
        header[0] = header[0].replace('# Headers:', '')
    elif not line.startswith('#'):
        data.append(line.rstrip().split(';'))

因此,您首先检查它是否以# Headers开头,如果是,请在单独的列表中捕获这些项目,然后,如果它不是标题,则执行现有的评论检查如果没有评论,请保存项目。

然后你有成对列表,可以压缩。

答案 2 :(得分:0)

这是非常简单的解决方案;此版本仅检测以完全字符串 # Headers:开头的标题行,以及其他简化,如果遇到标题行之前的数据行,则会引发异常。

我使用正则表达式或csv模块作为练习留下更强大的实现; - )

import StringIO

inf = StringIO.StringIO('''
# Date: 9/26/2014
# Time: 12:04 PM
# Source: XYZ Database
# User: green_bean_4_u
# Headers: tweet_type, user_screeenname, user_id, user_language, event_date
reply;tweeterA;10001;en;9/6/2014m
mention;tweeterB;10002;en;9/6/2014m
retweet;tweeterC;10003;ar;9/6/2014m
mention;tweeterC;10003;ar;9/7/2014m
retweet;tweeterA;10001;en;9/8/2014m
reply;tweeterZ;100026;fr;9/30/2014m
''')

headers = None
for line in inf:
    print line
    if line.startswith('# Headers:'):
        header_string = line[10:]
        headers = [x.strip() for x in header_string.split(',')]

    elif line.startswith('#') or not line.strip():
        # skip all other commented or blank lines
        pass

    else:
        if headers is None:
            raise RuntimeError("no header line encountered!")

        d = dict(zip(headers, line.strip().split(';')))
        print d

答案 3 :(得分:0)

headers = []
answer = {}
with open('path/to/file') as infile:
    for line in infile:
        if line.startswith("# Headers:"):
            headers = line.strip().split(":",1)[1].split(',')
            for h in headers:
                if h not in answer:
                    answer[h] = []
        elif not line.startswith("#"):
            vals = line.strip().split(';')
            for h,v in zip(headers, vals):
                answer[h].append(v)