Найти и заменить в CSV-файлах Python - PullRequest
0 голосов
/ 14 октября 2010

В связи с предыдущим вопросом , я пытаюсь заменить несколько больших файлов 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 ]

3 голосов
/ 14 октября 2010

Есть множество вещей, которые вы можете сделать, чтобы ускорить это:

Сначала используйте модуль csv. Это обеспечивает эффективные и без ошибок методы для чтения и записи файлов CSV. В частности, вам интересен объект DictReader: он будет представлять каждую строку, которую он читает из файла, в виде словаря с указанием имени столбца.

Во-вторых, компилируйте свои регулярные выражения один раз, а не каждый раз, когда вы их используете. Сохраните скомпилированные регулярные выражения в словаре, снабженном столбцом, к которому вы собираетесь их применить.

В-третьих, учтите, что если вы примените сто регулярных выражений к длинной строке, вы будете сканировать строку от начала до конца сто раз. Это может быть не лучшим подходом к вашей проблеме; вам, возможно, лучше потратить некоторое время на подход, который позволит вам прочитать строку от начала до конца один раз.

1 голос
/ 14 октября 2010

Вам не нужно 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']]
0 голосов
/ 14 октября 2010

Так что, если это так, и все 10 столбцов имеют одинаковые имена каждый раз, но не в порядке, (я не уверен, что это то, что вы делаете там, но здесь), оставьте один массив дляимена заголовков и по одному для каждого столбца, разбитого на элементы (должно быть по 10 элементов в каждой строке), теперь просто смещаем регулярное выражение, выполняя комбо case / select, сравниваем номер элемента массива заголовков, а затем внутри кейса ссылаемся намассив данных с одинаковым смещением, так как имя - это то, что попадет в правильный регистр, вы должны иметь возможность использовать одни и те же 10 регулярных выражений, и вам не придется каждый раз перекомпилировать новую «команду».

Iнадеюсь, что это имеет смысл.Извините, я не знаю синтаксис, чтобы помочь вам, но я надеюсь, что моя идея - это то, что вы ищете EDIT: IE

инициализирует все регулярные выражения перед запуском ваших циклов.

затем после чтения строки (и после строки заголовка)

выберите массив [n]

case "column1"

regex (data [0]);

case "column2"

regex (data [1]);,,,,end select

Это должно вызвать правильное регулярное выражение для правых столбцов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...