使用Python查找和替换CSV文件

时间:2010-10-14 14:21:20

标签: python performance function dictionary csv

a previous question相关,我正在尝试替换多个大型CSV文件。

列顺序(和内容)在文件之间发生变化,但是对于每个文件,我想要大约10列,并且可以通过列标题名称进行标识。我也想为每一列提供1-2个词典。因此,对于我想要的列,我只想使用正确的字典,并希望按顺序实现它们。

我试图解决这个问题的一个例子:

# -*- coding: utf-8 -*-
import re

# imaginary csv file. pretend that we do not know the column order.
Header = [u'col1', u'col2']
Line1 = [u'A',u'X']
Line2 = [u'B',u'Y']
fileLines = [Line1,Line2]

# dicts to translate lines
D1a = {u'A':u'a'}
D1b = {u'B':u'b'}
D2 = {u'X':u'x',u'Y':u'y'}

# dict to correspond header names with the correct dictionary.
# i would like the dictionaries to be read sequentially in col1.
refD = {u'col1':[D1a,D1b],u'col2':[D2]}

# clunky replace function
def freplace(str, dict):
    rc = re.compile('|'.join(re.escape(k) for k in dict))
    def trans(m):
        return dict[m.group(0)]
    return rc.sub(trans, str)

# get correspondence between dictionary and column
C = []
for i in range(len(Header)):
    if Header[i] in refD:
        C.append([refD[Header[i]],i])

# loop through lines and make replacements
for line in fileLines:
    for i in range(len(line)):
        for j in range(len(C)):
            if C[j][1] == i:
                for dict in C[j][0]:
                    line[i] = freplace(line[i], dict)

我的问题是这段代码很慢,我无法弄清楚如何加快速度。 我是初学者,我的猜测是我的freplace函数在很大程度上减慢了速度,因为它必须为每一行中的每一列编译。我想从该函数中取出rc = re.compile('|'.join(re.escape(k) for k in dict))行,但不知道如何做到这一点并仍然保留我的其余代码所做的事情。

3 个答案:

答案 0 :(得分:3)

你可以做很多事情来加快速度:

首先,使用csv模块。它为读取和写入CSV文件提供了高效且无错误的方法。特别是DictReader对象是您感兴趣的对象:它将从文件中读取的每一行都显示为由其列名称键入的字典。

其次,编译你的正则表达式,而不是每次使用它们。将已编译的正则表达式保存在由您要应用它们的列键入的字典中。

第三,考虑如果你将一百个正则表达式应用于长字符串,那么你将从头到尾扫描字符串一百次。这可能不是解决问题的最佳方法;你可能最好花一些时间在一个让你从头到尾读取字符串的方法。

答案 1 :(得分:1)

您不需要re

# -*- coding: utf-8 -*-

# imaginary csv file. pretend that we do not know the column order.
Header = [u'col1', u'col2']
Line1 = [u'A',u'X']
Line2 = [u'B',u'Y']
fileLines = [Line1,Line2]

# dicts to translate lines
D1a = {u'A':u'a'}
D1b = {u'B':u'b'}
D2 = {u'X':u'x',u'Y':u'y'}

# dict to correspond header names with the correct dictionary
refD = {u'col1':[D1a,D1b],u'col2':[D2]}

# now let's have some fun...

for line in fileLines:
    for i, (param, word) in enumerate(zip(Header, line)):
        for minitranslator in refD[param]:
            if word in minitranslator:
                line[i] = minitranslator[word]

返回:

[[u'a', u'x'], [u'b', u'y']]

答案 2 :(得分:0)

所以如果是这样的话,并且所有10列每次都有相同的名称,但是不按顺序,(我不确定这是你在那里做的,但是这里有)保留一个数组标题名称,每个列分成一个元素(每行应该是10个项目),现在只需通过一个case / select组合来偏移正则表达式,比较标题数组的元素编号,然后在case中,引用数据数组在相同的偏移量,因为名称是正确的情况下你应该能够重复使用相同的10个正则表达式,而不必每次都重新编译一个新的“命令”。

我希望这是有道理的。对不起,我不知道帮助你的语法,但我希望我的想法是你正在寻找的 编辑: 即。

在开始循环之前初始化所有正则表达式。

然后在你读了一行之后(在标题行之后)

选择array [n]

案例“column1”

正则表达式(数据[0]);

案例“column2”

正则表达式(数据[1]); 。 。 。 。 结束选择

这应该为正确的列调用正确的正则表达式