【问题标题】:How to search for multiple data from multiple lines and store them in dictionary?如何从多行中搜索多个数据并将它们存储在字典中?
【发布时间】:2016-06-23 09:00:11
【问题描述】:

假设我有一个包含以下内容的文件:

/* Full name: abc */
.....
.....(.....)
.....(".....) ;
/* .....
/* .....
..... : "....."
}
"....., .....
Car : true ;
House : true ;
....
....
Age : 33
....
/* Full name: xyz */
....
....
Car : true ;
....
....
Age : 56
....

我只对每个人的全名、汽车、房屋和年龄感兴趣。我感兴趣的变量/属性之间还有许多其他格式不同的数据行。

到目前为止我的代码:

import re

initial_val = {'House': 'false', 'Car': 'false'}

with open('input.txt') as f:
    records = []
    current_record = None
    for line in f:
        if not line.strip():
            continue
        elif current_record is None:
            people_name = re.search('.+Full name ?: (.+) ', line)
            if people_name:
                current_record = dict(initial_val, Name = people_name.group(1))
            else:
                continue
        elif current_record is not None:
            house = re.search(' *(House) ?: ?([a-z]+)', line)
            if house:
                current_record['House'] = house.group(2)
            car = re.search(' *(Car) ?: ?([a-z]+)', line)
            if car:
                current_record['Car'] = car.group(2)
            people_name = re.search('.+Full name ?: (.+) ', line)
            if people_name:
                records.append(current_record)
                current_record = dict(initial_val, Name = people_name.group(1))                       

print records

我得到了什么:

[{'Name': 'abc', 'House': 'true', 'Car': 'true'}]

我的问题:

我想如何提取数据并将其存储在字典中,例如:

{'abc': {'Car': true, 'House': true, 'Age': 33}, 'xyz':{'Car': true, 'House': false, 'Age': 56}}

我的目的:

检查每个人是否有车、房子和年龄,如果没有则返回false

我可以将它们打印在这样的表格中:

Name Car House Age
abc true true 33
xyz true false 56

请注意,我使用的是 Python 2.7,我不知道每个人的每个变量/属性(例如 abc、true、true、33)的实际值是多少。

我的问题的最佳解决方案是什么?谢谢。

【问题讨论】:

    标签: python regex python-2.7 dictionary


    【解决方案1】:

    好吧,你只需要跟踪当前记录:

    def parse_name(line):
        # first remove the initial '/* ' and final ' */'
        stripped_line = line.strip('/* ')
        return stripped_line.split(':')[-1]
    
    
    WANTED_KEYS = ('Car', 'Age', 'House')
    
    # default values for when the lines are not present for a record
    INITIAL_VAL = {'Car': False, 'House': False, Age: -1}
    
    with open('the_filename') as f:
        records = []
        current_record = None
    
        for line in f:
            if not line.strip():
                 # skip empty lines
                 continue
            elif current_record is None:
                 # first record in the file
                 if line.startswith('/*'):
                     current_record = dict(INITIAL_VAL, name=parse_name(line))
                 else:
                     # this should probably be an error in the file contents
                     continue
            elif line.startswith('/*'):
                # this means that the current record finished, and a new one is starting
                records.append(current_record)
                current_record = dict(INITIAL_VAL, name=parse_name(line))
            else:
                key, val = line.split(':')
                if key.strip() in WANTED_KEYS:
                    # we want to keep track of this field
                    current_record[key.strip()] = val.strip()
                # otherwise just ignore the line
    
    
    print('Name\tCar\tHouse\tAge')
    for record in records:
        print(record['name'], record['Car'], record['House'], record['Age'], sep='\t')
    

    请注意,对于Age,您可能希望使用int 将其转换为整数:

    if key == 'Age':
        current_record['Age'] = int(val)
    

    上面的代码生成了一个字典列表,但是很容易将其转换为字典字典:

    new_records = {r['name']: dict(r) for r in records}
    for val in new_records.values():
        del val['name']
    

    new_records 之后会是这样的:

    {'abc': {'Car': True, 'House': True, Age: 20}, ...}
    

    如果您在有趣的行之间有其他格式不同的行,您可以简单地编写一个返回TrueFalse 的函数,具体取决于行是否为您需要的格式,并将其用于filter文件的行:

    def is_interesting_line(line):
        if line.startswith('/*'):
            return True
        elif ':' in line:
            return True
    
    for line in filter(is_interesting_line, f):
        # code as before
    

    更改is_interesting_line 以满足您的需求。最后,如果您必须处理几种不同的格式等,也许使用正则表达式会更好,在这种情况下,您可以执行以下操作:

    import re
    
    LINE_REGEX = re.compile(r'(/\*.*\*/)|(\w+\s*:.*)| <other stuff>')
    
    def is_interesting_line(line):
        return LINE_REGEX.match(line) is not None
    

    如果您愿意,您可以获得表格的更精美的格式,但您可能首先需要确定名称的最大长度等,或者您可以使用类似 tabulate 的东西来为您完成。

    例如类似(未测试):

    max_name_length = max(max(len(r['name']) for r in records), 4)
    format_string = '{:<{}}\t{:<{}}\t{}\t{}'
        print(format_string.format('Name', max_name_length, 'Car', 5,  'House', 'Age'))
        for record in records:
            print(format_string.format(record['name'], max_name_length, record['Car'], 5, record['House'], record['Age']))
    

    【讨论】:

    • 非常感谢您的帮助。但是,在您编写“key, val = line.split(':')”的部分对我不起作用,因为在这些属性/变量之间还有其他数据行不是 (key : value ;),我可以知道我应该做些什么改变吗?
    • @user3118123 循环一次处理一行。 如果文件采用您描述的格式,即something : value 形式的行,那么它应该可以工作。因为在循环的一次迭代中line 将是字符串Age: 33 然后line.split(':') 返回列表['Age', '33'],所以你有key = Ageval = 33。如果不是这种情况,您应该明确说明您正在处理的文件格式,也许提供一个假的但格式准确的实际示例。
    • 很抱歉没有提供足够的信息,我已经编辑了文件内容。基本上,该文件有许多不同格式的行。使用正则表达式会更好吗?但我也不确定如何使用正则表达式。
    • @user3118123 您可以简单地过滤之前的行。或者实际上你可以在line.split(':') 之前添加一个if ':' not in line: continue。编辑了答案。
    • 我决定使用正则表达式来执行我的搜索。但是,我没有得到我想要的输出(仅测试 NameHouse)。我已经添加了我的代码。您能否帮我修改我的代码,了解如何将 false 分配给变量(如果找不到)以及如何将数据存储在字典中以便我想获得类似您的 new_records 的东西?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多