Сценарий Sed для редактирования файла CSV Или Python

В нашем проекте мы должны импортировать файл CSV в пост-ГРЭС. Существует несколько типов файлов, означающих длину изменений файла, как некоторые файлы с меньшим количеством столбцов и некоторыми со всеми ними.

Нам нужен быстрый способ импортировать этот файл в пост-ГРЭС. Я хочу использовать КОПИЮ С пост-ГРЭС, так как требование к скорости обработки очень высоко (почти 150 файлов в минуту с 20K размером файла каждый).

Так как числа столбцов файла не фиксируются, я должен предварительно обработать файл, прежде чем я передам его процедуре пост-ГРЭС. Предварительная обработка должна просто добавить дополнительные запятые в csv для столбцов, которые не находятся там в файле.

Существует две опции для меня предварительно обработать файл - Python использования или использовать Sed.

Мой первый вопрос, каков был бы самый быстрый способ, предварительно обрабатывают файл?

Второй вопрос, Если бы я использую sed, как я вставил бы запятую после того, как говорят 4-е, 5-е поля запятой?
например, если файл имеет записи как 1,23,56, мы, 89,2009-12-06, и я должен отредактировать файл с окончательным результатом как: 1,23,56, мы, 89, 06.12.2009

5
задан Sujit 2 March 2010 в 23:21
поделиться

6 ответов

Известно ли вам, что КОПИРОВАТЬ ИЗ позволяет указать, какие столбцы (а также в каком порядке) должны быть import?

COPY tablename ( column1, column2, ... ) FROM ...

Прямое указание на уровне Postgres столбцов для импорта и в каком порядке обычно является самым быстрым и эффективным методом импорта.

Как уже было сказано, существует гораздо более простой (и переносимый) способ использования sed (чем то, что было представлено в других сообщениях) для замены n th вхождение , например замените 4-е и 5-е вхождения запятой на двойные:

echo '1,23,56,we,89,2009-12-06' | sed -e 's/,/,,/5;s/,/,,/4'

дает:

1,23,56,we,,89,,2009-12-06

Обратите внимание, что я сначала заменил крайние правые поля (# 5).

Я вижу, что вы также пометили свой вопрос как связанный с perl , хотя вы не делаете явной ссылки на perl в тексте вопроса; вот одна возможная реализация, которая дает вам гибкость также переупорядочивания или другой обработки полей:

echo '1,23,56,we,89,2009-12-06' |
  perl -F/,/ -nae 'print "$F[0],$F[1],$F[2],$F[3],,$F[4],,$F[5]"'

также производит:

1,23,56,we,,89,,2009-12-06

Очень похоже на awk , для записи:

echo '1,23,56,we,89,2009-12-06' |
  awk -F, '{print $1","$2","$3","$4",,"$5",,"$6}'

Я оставлю Python кому-то другому.:)

Небольшое примечание к примеру Perl: я использую параметры -a и -F для автоматического разделения, поэтому у меня есть более короткая командная строка; однако при этом новая строка остается встроенной в последнее поле ( $ F [5] ), что нормально, если это поле не нужно переупорядочивать в другом месте. Если возникнет такая ситуация, потребуется немного больше ввода, чтобы вырезать новую строку с помощью chomp , затем разделить вручную и, наконец, напечатать наш собственный символ новой строки \ n ] (приведенный выше пример awk не имеет этой проблемы):

perl -ne 'chomp;@F=split/,/;print "$F[0],$F[1],$F[2],$F[3],,$F[4],,$F[5]\n"'

РЕДАКТИРОВАТЬ (идея, вдохновленная Вивин):

COMMAS_TO_DOUBLE="1 4 5"
echo '1,23,56,we,89,2009-12-06' |
  sed -e `for f in $COMMAS_TO_DOUBLE ; do echo "s/,/,,/$f" ; done |
    sort -t/ -k4,4nr | paste -s -d ';'`

1,,23,56,we,,89,,2009-12-06

Извините, не смог устоять. :)

3
ответ дан 14 December 2019 в 08:48
поделиться

Чтобы ответить на ваш первый вопрос, sed будет иметь меньше накладных расходов, но может быть болезненным. awk было бы немного лучше (он более мощный). Perl или Python имеют больше накладных расходов, но с ними легче работать (что касается Perl, это, возможно, немного субъективно;). Лично я бы использовал Perl).

Что касается второго вопроса, я думаю, что проблема может быть немного сложнее. Например, разве вам не нужно исследовать строку, чтобы выяснить, какие поля на самом деле отсутствуют? Или гарантировано, что всегда будет 4-й и 5-й? Если это первый случай, было бы способом проще сделать это в Python или Perl, чем в sed . В противном случае:

echo "1,23,56,we,89,2009-12-06" | sed -e 's/\([^,]\+\),\([^,]\+\),\([^,]\+\),\([^,]\+\),\([^,]\+\),/\1,\2,\3,\4,,\5,,/'

или (проще для глаз):

echo "1,23,56,we,89,2009-12-06" | sed -e 's/\(\([^,]\+,\)\{3\}\)\([^,]\+\),\([^,]\+\),/\1,\3,,\4,,/'

Это добавит запятую после 5-го и 4-го столбцов, если в тексте нет других запятых.

Или вы можете использовать два sed для чего-то менее уродливого (хотя и немного):

echo "1,23,56,we,89,2009-12-06" | sed -e 's/\(\([^,]*,\)\{4\}\)/\1,/' | sed -e 's/\(\([^,]*,\)\{6\}\)/\1,/'
2
ответ дан 14 December 2019 в 08:48
поделиться

@OP, вы обрабатываете CSV-файл с отдельными полями и разделителями. Используйте инструмент, который может разделять разделители и предоставлять поля для удобной работы. sed не является одним из них, хотя это можно сделать, как предлагали некоторые из ответов, но вы получите регулярное выражение sed, которое трудно читать, когда оно усложняется. Используйте такие инструменты, как awk / Python / Perl, где они легко работают с полями и разделителями, лучше всего, доступны модули, специально предназначенные для обработки csv. Для вашего примера простой подход Python (без использования модуля csv, который в идеале вы должны попробовать его использовать)

for line in open("file"):
    line=line.rstrip() #strip new lines
    sline=line.split(",")
    if len(sline) < 8: # you want exact 8 fields
        sline.insert(4,"")
        sline.insert(6,"")
        line=','.join(sline)
    print line

output

$ more file
1,23,56,we,89,2009-12-06

$ ./python.py
1,23,56,we,,89,,2009-12-06
2
ответ дан 14 December 2019 в 08:48
поделиться
sed 's/^([^,]*,){4}/&,/' <original.csv >output.csv

Добавляет запятую после 4-го поля, разделенного запятой (путем сопоставления 4 повторений , , а затем добавления запятой после этого). Обратите внимание, что здесь есть загвоздка; убедитесь, что ни одно из этих значений не является строкой в ​​кавычках с запятыми.

Вы можете связать несколько замен через каналы, если это необходимо, или изменить регулярное выражение, чтобы добавить любые необходимые запятые одновременно (хотя это становится более сложным; вам нужно будет использовать захват подгрупп в вашем тексте замены).

0
ответ дан 14 December 2019 в 08:48
поделиться

Не знаю относительно скорости, но вот выражение sed, которое должен выполнить свою работу:

sed -i 's/\(\([^,]*,\)\{4\}\)/\1,/' file_name

Просто замените 4 желаемым количеством столбцов

0
ответ дан 14 December 2019 в 08:48
поделиться

В зависимости от ваших требований, рассмотрите возможность использования ETL программного обеспечения для этой и будущих задач. Такие инструменты, как Pentaho и Talend, предлагают большую гибкость, и вам не придется писать ни строчки кода.

0
ответ дан 14 December 2019 в 08:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: