我必须从文件(.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€
你能帮我吗?
答案 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() }
`