Python:将多个.txt文件解析为单个.csv文件?

时间:2012-03-27 08:44:06

标签: python database parsing csv

我对Python中复杂的大规模解析没有经验,你们有没有关于如何轻松解析不同格式的多个文本文件的任何提示或指南,并将它们组合成一个.csv文件并最终进入他们进入数据库?

文本文件的示例如下:

general.txt(姓名 - 部门(DEPT)会议室#[年龄]

John Doe -- Management (MANG) 205 [Age: 40]
Equipment: Laptop, Desktop, Printer, Stapler
Experience: Python, Java, HTML
Description: Hardworking, awesome

Mary Smith -- Public Relations (PR) 605 [Age: 24] 
Equipment: Mac, PC
Experience: Social Skills
Description: fun to be around

Scott Lee -- Programmer (PG) 403 [Age: 25]
Equipment: Personal Computer
Experience: HTML, CSS, JS
Description: super-hacker

Susan Kim -- Programmer (PG) 504 [Age: 21]
Equipment: Desktop
Experience: Social Skills
Descriptions: fun to be around

Bob Simon  -- Programmer (PG) 101 [Age: 29]
Equipment: Pure Brain Power
Experience: C++, C, Java 
Description: never comes out of his room

cars.txt(按部门/房间拥有汽车的人员名单#)

Programmer: PG 403, PG 101
Management: MANG 205

house.txt

Programmer: PG 504

最终的csv最好应列表为:

Name     | Division    | Division Abbrevation | Equipment | Room | Age | Car? | House? |
Scott Lee  Programming          PG                 PC        403   25     YES     NO 
Mary Smith Public Rel.          PR               Mac, PC     605   24      NO     NO

最终目标是拥有一个数据库,其中搜索“PR”将返回人员部门为“PR”的每一行。总共可能有30个文本文件,每个文本文件代表数据库中的一个或多个列。有些列是短段,其中包括逗号。总共约10,000行。我知道Python内置了csv,但我不知道从哪里开始,以及如何以1 csv结束。有什么帮助吗?

4 个答案:

答案 0 :(得分:1)

看起来你正在寻找能为你解决整个问题的人。我在这里:))

一般的想法是将一般信息解析为dict(使用正则表达式),然后向其附加其他字段,最后写入CSV。这里是Python 3.x解决方案(我认为Python 2.7+应该足够了):

import csv
import re


def read_general(fname):
    # Read general info to dict with 'PR 123'-like keys

    # Gerexp that will split row into ready-to-use dict
    re_name = re.compile(r'''
        (?P<Name>.+)
        \ --\  # Separator + space
        (?P<Division>.+)
        \  # Space
        \(
            (?P<Division_Abbreviation>.*)
        \)
        \  # Space
        (?P<Id>\d+)
        \  # Space
        \[Age:\  # Space at the end
            (?P<Age>\d+)
        \]
        ''', re.X)

    general = {}

    with open(fname, 'rt') as f:
        for line in f:
            line = line.strip()
            m = re_name.match(line)

            if m:
                # Name line, start new man
                man = m.groupdict()
                key = '%s %s' % (m.group('Division_Abbreviation'), m.group('Id'))
                general[key] = man

            elif line:
                # Non empty lines
                # Add values to dict
                key, value = line.split(': ', 1)
                man[key] = value

    return general


def add_bool_criteria(fname, field, general):
    # Append a field with YES/NO value

    with open(fname, 'rt') as f:
        yes_keys = set()

        # Phase one, gather all keys
        for line in f:
            line = line.strip()
            _, keys = line.split(': ', 1)

            yes_keys.update(keys.split(', '))

        # Fill data
        for key, man in general.items():  # iteritems() will be faster in Python 2.x
            man[field] = 'YES' if key in yes_keys else 'NO'


def save_csv(fname, general):
    with open(fname, 'wt') as f:
        # Gather field names
        all_fields = set()
        for value in general.values():
            all_fields.update(value.keys())

        # Write to csv
        w = csv.DictWriter(f, all_fields)
        w.writeheader()
        w.writerows(general.values())


def main():
    general = read_general('general.txt')
    add_bool_criteria('cars.txt', 'Car?', general)
    add_bool_criteria('house.txt', 'House?', general)
    from pprint import pprint
    pprint(general)
    save_csv('result.csv', general)


if __name__ == '__main__':
    main()

我希望你有很多$$$;)

旁注

CSV是一种历史记录,您可以使用JSON进行存储和进一步使用,因为它使用起来更简单,更灵活,更易于阅读。

答案 1 :(得分:0)

你只有一个解析一个文件的函数,并返回一个包含{'name': 'Bob Simon', 'age': 29, ...}等字典的列表。然后在每个文件上调用它,扩展一个主列表。然后将此主要的dicts列表写为CSV文件。

更精心地说:

首先你需要解析输入文件,你需要一个接收文件的函数,然后返回一个“东西”列表。

def parse_txt(fname):
    f = open(fname)

    people = []

    # Here, parse f. Maybe using a while loop, and calling
    # f.readline() until there is an empty line Construct a
    # dictionary from each person's block, and append it to allpeople

    return people

返回类似于:

的内容
people = [
    {'name': 'Bob Simon', 'age': 29},
    {'name': 'Susan Kim', 'age': 21},
]

然后,遍历每个输入文件(可能使用os.listdiroptparse来获取args列表):

allpeople = []
for curfile in args:
     people = parse_txt(fname = curfile)
     allpeople.extend(people)

所以allpeople是所有文件中所有人的长列表。

最后,您可以使用csv module将其写入CSV文件(此位通常涉及另一个函数,将数据重新组织为与编写器模块更兼容的格式)

答案 2 :(得分:0)

我会向后做,我首先将所有那些house.txt和cars.txt加载到一个dict中,看起来像:

cars = {'MANG': [205], 'PG': [403, 101]}

既然你说它们中有30个,你就可以轻松地使用嵌套的字典,而不会让事情太复杂:

data = {'house': {'PG': 504}, 'cars': {...}}

一旦data dict完成,加载general.txt并在为每个员工(或其他任何人)建立dict时,做一个dict查找,看看他们是否有房子,或者汽车等..

例如对于John Doe,你必须检查:

if data['house']['PG'].get(205):
    # ...

并相应地更新他的dict。显然,您不必对所有可能的查找进行硬编码,只需构建一些['house', 'cars', ...]或类似的列表并迭代它。

最后你应该有一个大的dict列表,所有信息都已合并,所以只需将它们中的每一个写入csv文件。

答案 3 :(得分:0)

最好的建议:不要这样做。

你的车和房子的关系很有意思。拥有房屋或汽车是个人或其他实体的属性(公司,合伙企业,共同租赁,共同租赁等)。它不是(“分区”,房间)组合的属性。您的汽车文件中的第一个事实是“403房间的程序员拥有一辆汽车”。在同一个房间里有2个或更多程序员的不太可能的事件会发生什么?

设备不应列入清单。

不要记录年龄,记录日期或出生年份。

您需要在数据库中使用多个表,而不是1个CSV文件。你需要学习一本关于基础数据库设计的书。