从文件中提取不同大小的数组

时间:2016-05-16 18:58:34

标签: python arrays database csv extract

我必须从文件(.csv或.txt)中提取表格,假设文件是​​csv 此文件中有不同的表,大小不同(500x5,200x3,...) 我需要在不同的数组中提取它们,以便将它们加载到数据库中

我的档案结构:

Book of sales du 01/01/2014 au 31/12/2050;;;;;;;;;;;

Sales;;;;;;;;;;;

Date;Invoice;Client;Txt;Price

19/02/2015;1;Johnny;coloris: 002, taille: 54/18;82,03€

21/02/2015;2;Florian;coloris: 005PL, taille: 56/17;78,34€
Total;;;;10 700,74€

;;;;;;;;;;;

Avoirs générés;;;;;;;;;;;

Date;N° Avoir;Client

04/03/2015;1;Johnny

28/03/2015;2;Jacques-Elie

Total;;698,45€

你能帮我吗?

2 个答案:

答案 0 :(得分:0)

要处理此数据,您需要编写一个简单的解析器。

解析器是一个小型状态机。根据当前状态和它接下来看到的输入,它会移动到某个新状态。当它在状态之间移动时,它收集输入并创建某种树结构。您可以尝试通过绘制每个状态的圆圈和连接它们的线来形象化,因为我描述了解析器需要经历的状态。使用您需要的输入标记每一行,以便在状态之间移动。

您的数据以初始状态(等待标题)开始,期望标题行包含日期范围:

Book of sales du 01/01/2014 au 31/12/2050;;;;;;;;;;;

您需要读取该行,检查它是否与预期格式匹配,提取并保留日期范围,然后移至下一个状态(等待表)。

您的表似乎以一个名称后跟11个分号开头。例如:

Sales;;;;;;;;;;;

如果检测到以11个分号结尾的行,则需要启动具有给定表名的新表并移至state(期望字段名称)。

字段名称是以分号分隔的字符串:

Date;Invoice;Client;Txt;Price

您需要在分号上拆分标题行,保存字段名称并移至新状态(处理数据)。

您的数据实际上与标题相同,是由分号分隔的字段值:

19/02/2015;1;Johnny;coloris: 002, taille: 54/18;82,03€

再次,你阅读,分裂和保存。这次你保持当前状态(处理数据),因为表中可能有多条记录。

表的摘要行具有相同的字段,在这种情况下使用Total而不是Date:

Total;;;;10 700,74€

因此,如果您在(处理数据)中看到以“总计”开头的行,则转换到状态(摘要)并保存总计。

从(摘要),您转换到(结束表),这是一行分号:

;;;;;;;;;;;

或者这可能是一个空表,并不是每个表都以分号结尾。我无法分辨,因为您的样本数据集只有两个表,最后一个表位于文件的末尾。

处理完(结束表)后,转换回(等待表),为下一个表做好准备。如果你看到文件的结尾,那么你转换到(最终状态),你就完成了解析。

由于标题,数据和摘要行都是基本相同的结构,我们可以将它们折叠成单个状态(处理数据),在完成处理之后,我们可以特别处理表的第一行和最后一行。它们很容易找到。这使得解析器更简单,更容易调试。

类似地,如果我们引入空表的概念,我们可以进一步简化我们的解析器,因为我们不需要(结束表)状态。我们只是将它视为没有标题,数据或摘要的空表的开头。当我们完成解析时,很容易忽略空表。此外,我们可以假装第一个表在空表之后开始,因此我们可以从(处理数据)状态开始并使一切正常。

输入中每一行之间的空白行(可能是从窗口返回的车行+换行符)可以被删除。

将它组合在一起,解析器变为:

with open file:
    # transition to (awaiting header)
    read header
    # transition to (processing data)
    current table = empty
    for each line:
        # strip blank
        if blank: # blank does not change state
            continue
        if new table line:  
            # transition to (new table)
            save current table if any
            make new table and set it to current table
            # transition to (processing data)
        else:
            # transition to (processing data)
            split line into data columns
            # stay in (processing data)
    save current table if any
    # transition to (final state)

让这更像pythonic:

tables = []
with open(filename) as file:
    line = file.readline()
    start_date, end_date = line[17:27], line[31:41]
    table_name, table_rows = "", [] # pretend we start with a blank table
    for line in file:              # reads lines one at a time until the end
        line = line.strip()        # remove linefeed from end of line
        if not line:               # check for blank line
            continue
        if line.endswith(';'*11):  # line ends with 11 semicolons
            # save the existing table; the first table will be blank
            tables.append((table_name, table_rows))
            table_name = line[:-11]  # name is all but the last 11 semicolons
            table_rows = []
        else:
            fields = line.split(';')
            table_rows.append(fields)
    # save the current table
    table.append((table_name, table_rows))

您现在应该有一个表列表(其中一些可能是空的)。

# maybe record start_date, end_date
# process each table
for table_name, table_rows in tables:
    if not table_rows: # table is blank
        continue

    fields = table_rows[0]
    if table_rows[-1][0] == "Total":
        rows = table_rows[1:-1]
        summary = table_rows[-1]
    else:
        rows = table_rows[1:]
        summary = None
    save_table(table_name, fields, rows, summary)

这个解析器起初很简单,我们采用了一些快捷方式使其更简单。

如果语言稍微复杂一些,我们会把它留在更抽象的形式:

state = 0
for line in file:
    if state == 0:
        if line matches transition from 0 to 0:
            state = 0
            save line data for state 0
        elif line matches transition from 0 to 1:
            state = 1
            save line data for state 1
        elif line matches transition from 0 to 2:
            ...
    elif state == 1: 
        if line matches transition from 1 to 0:
            state = 0
            save line data for state 0
        elif line matches transition from 1 to 1:
            state = 1
            save line data for state 1
        elif line matches transition from 1 to 2:
            ...
    elif state == 2:
        ...

本文中的想法将涵盖您需要处理的大部分数据。

对于具有深度嵌套结构的更复杂的数据格式,您必须将起始结构与结束结构匹配,您需要使用真正的解析器,例如pyparsing提供的。如果没有解析器工具,即使是带括号的简单数学表达式也很难。

答案 1 :(得分:0)

感谢您的回复

我写了这个: `     线= []     打开(路径+" CaParArticle.csv")作为tt:         content = [line.strip()for line in tt.readlines()]

import re
re.findall("Date..",content[3])

idx_date=[i for i, item in enumerate(content) if re.search('Date', item)]
idx_total=[i for i, item in enumerate(content) if re.search('Total [^H^T]|TOTAL [^H^T]', item)]
tab={}
tit={}
for i in range( len(idx_date) ):
tab[i]=pd.DataFrame( [ sub.split(";") for sub in content[idx_date[i]+1:idx_total[i]] ], \
        columns=content[idx_date[i]].split(";")  )
    tit[i]=content[idx_total[i]][6: content[idx_total[i]].index(";")-1  ]\
        .replace('des ','').upper().replace(' ','_')

tab={ tit[key]: value for key,value in tab.items()  }

`