用Python在CSV文件中查找和替换
这段内容和之前的问题有关,我正在尝试对多个大型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 个回答
如果是这样的话,假设这10列的名字每次都是一样的,只是顺序不同(我不确定你是不是在做这个,但我就这样说吧),你可以先准备一个数组来存放列名,再准备一个数组来存放每一列的数据(每行应该有10个数据)。接下来,你可以通过一个选择结构来调整正则表达式的使用,比较一下你的列名数组的元素位置,然后在选择结构里面,按照相同的位置引用数据数组。因为列名会帮助你找到正确的顺序,所以你应该可以重复使用同样的10个正则表达式,而不需要每次都重新编写新的“命令”。
希望这样说你能明白。抱歉我不知道具体的语法来帮你,但我希望我的想法是你需要的。
也就是说:
在开始循环之前,先初始化所有的正则表达式。
然后在你读取一行数据(在读取列名那一行之后)的时候,
选择数组[n]
如果是“column1”
就用正则表达式处理(data[0]);
如果是“column2”
就用正则表达式处理(data[1]);
……
最后结束选择结构。
这样就能为正确的列调用正确的正则表达式了。
有很多方法可以让这个过程更快:
首先,使用 csv
模块。这个模块提供了高效且没有错误的方法来读取和写入 CSV 文件。特别是 DictReader
对象,它会把从文件中读取的每一行都呈现为一个字典,字典的键是列名。
其次,编译你的正则表达式(regex)只需要做一次,而不是每次使用时都编译。把编译好的正则表达式保存在一个字典里,字典的键是你要应用它们的列名。
第三,考虑一下,如果你对一个长字符串应用一百个正则表达式,你就得从头到尾扫描这个字符串一百次。这可能不是解决问题的最佳方法;你可能更应该花点时间寻找一种方法,让你只需从头到尾读取一次字符串。
你不需要用到 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']]