2009-07-23 3 views
2

У меня есть набор из 4 массивных CSV-файлов, которые мне нужно изменить. То, что мне нужно сделать, это совпадение с этим выражением /^(.*),,/, скопируйте атом, а затем добавьте его к каждой последующей строке, пока атом не будет повторен. Затем мне нужно промыть и повторить до конца файла (каждый файл имеет около 25 тыс. Строк в нем). Наконец, мне нужно вернуться и удалить первый атом.Манипулирование огромными CSV-файлами с помощью sed

Я хотел бы использовать sed для этого, если это возможно. Я попытался сделать это с помощью vim, но не смог правильно получить регулярное выражение. Любая помощь будет принята с благодарностью. Пример показан ниже:

До:

0917,, 
,882-1273,1 
,95F 9475,1 
,276-080,1 
,40K 0080,1 
,275-690A,1 
,TX-2311,3 
,TX-3351,4 
,B-07432,1 
,B-6901,1 
,23-753,1 
,02F 4307,1 
,5.1K QBK-ND,1 
,0944-026,1 
,0944-027,1 
,0944-004,1 
,0944-056,1 
,0944-057,1 
,0944-082,1 
,0944-024,1 
,0944-025,1 
,0944-102,4 
,LOR 102,1 
0918,, 
,CJ1085,1 
,1352-152,4 
,DMS3102A-18-,1 
,6-32 KEP,7 
,6-32 X 3/4,4 
,6-32X1/2,4 
,1251-102,8 
,Oct-32,4 
,10-32 SAE,8 

После:

0917,882-1273,1 
0917,95F 9475,1 
0917,276-080,1 
0917,40K 0080,1 
0917,275-690A,1 
0917,TX-2311,3 
0917,TX-3351,4 
0917,B-07432,1 
0917,B-6901,1 
0917,23-753,1 
0917,02F 4307,1 
0917,5.1K QBK-ND,1 
0917,0944-026,1 
0917,0944-027,1 
0917,0944-004,1 
0917,0944-056,1 
0917,0944-057,1 
0917,0944-082,1 
0917,0944-024,1 
0917,0944-025,1 
0917,0944-102,4 
0917,LOR 102,1 
0918,CJ1085,1 
0918,1352-152,4 
0918,DMS3102A-18-,1 
0918,6-32 KEP,7 
0918,6-32 X 3/4,4 
0918,6-32X1/2,4 
0918,1251-102,8 
0918,Oct-32,4 
0918,10-32 SAE,8 
+2

Хороший вопрос!Проблема не слишком широка, у вас есть четкое описание того, что вы пытаетесь сделать, и у вас есть подробный пример ввода и желаемого вывода. Престижность к вам! Я желаю, чтобы более SO пользователи сформулировали свои запросы к этому стандарту. –

+0

Имеет ли этот набор данных когда-либо через Excel? Линия '0918, окт-32,4' выглядит подозрительно для меня. –

+0

Получали ли вы эти данные, вставив таблицу HTML в Excel? В этом случае вам лучше разобрать HTML, а не проходить через этот дополнительный шаг. См. http://search.cpan.org/perldoc/HTML::TableExtract –

ответ

2

Программа (python)

import csv 
infile=file("in","r") 
outfile=file("out","w") 
reader = csv.reader(infile , dialect='excel') 
writer = csv.writer(outfile , dialect='excel') 
current_header="" 
for inrow in reader: 
    if len(inrow[0].strip()) != 0: 
     current_header = inrow[0] 
     continue 

    writer.writerow([current_header]+inrow[1:]) 

infile.close() 
outfile.close() 
print "done" 

вход

0917,, 
,882-1273,1 
,95F 9475,1 
,276-080,1 
,40K 0080,1 
,275-690A,1 
,TX-2311,3 
,TX-3351,4 
,B-07432,1 
,B-6901,1 
,23-753,1 
,02F 4307,1 
,5.1K QBK-ND,1 
,0944-026,1 
,0944-027,1 
,0944-004,1 
,0944-056,1 
,0944-057,1 
,0944-082,1 
,0944-024,1 
,0944-025,1 
,0944-102,4 
,LOR 102,1 
0918,, 
,CJ1085,1 
,1352-152,4 
,DMS3102A-18-,1 
,6-32 KEP,7 
,6-32 X 3/4,4 
,6-32X1/2,4 
,1251-102,8 
,Oct-32,4 
,10-32 SAE,8 

Выход

0917,882-1273,1 
0917,95F 9475,1 
0917,276-080,1 
0917,40K 0080,1 
0917,275-690A,1 
0917,TX-2311,3 
0917,TX-3351,4 
0917,B-07432,1 
0917,B-6901,1 
0917,23-753,1 
0917,02F 4307,1 
0917,5.1K QBK-ND,1 
0917,0944-026,1 
0917,0944-027,1 
0917,0944-004,1 
0917,0944-056,1 
0917,0944-057,1 
0917,0944-082,1 
0917,0944-024,1 
0917,0944-025,1 
0917,0944-102,4 
0917,LOR 102,1 
0918,CJ1085,1 
0918,1352-152,4 
0918,DMS3102A-18-,1 
0918,6-32 KEP,7 
0918,6-32 X 3/4,4 
0918,6-32X1/2,4 
0918,1251-102,8 
0918,Oct-32,4 
0918,10-32 SAE,8 

Весело

+0

это потрясающе !!! ... большое вам спасибо. он отлично работал – bsisco

+0

Не в sed, но он по крайней мере решает проблему. –

+0

гораздо быстрее и короче тоже, я уверен ... я даже не думал использовать python! – bsisco

1

Поскольку синтаксис СЭД маскировочная и не использовать изо дня в день, а не говорить о ваших коллегах, этот код будет трудно поддерживать. Предпочтительным является решение Perl/awk.

В любом случае, here - лучший ручной инструмент, который я когда-либо видел.

удачи Дим

+0

Не отвечает на вопрос. «RTFM» - это не ответ. «Использовать другой язык» - это не ответ. «Используйте другой язык, и вот как вы можете это сделать». Ответ. Если вы предлагаете Perl, дайте пример Perl, как это сделать. –

+0

Как вы видите, дорогой А. Леви, все ответы используют языки высокого уровня. Угадай почему? sed, может быть, классный инструмент, но если вы не используете его агрессивно изо дня в день, то не приветствуется нечто более сложное, чем поиск и замена (s ///). Когда задан вопрос, законно поднимать вопрос «Зачем вам это нужно?», «Может быть, есть другой способ его решить?» и т. д. Это мое личное мнение, и если вы не согласны с тем, что это ваша собственная проблема. – dimba

1

Perl может быть проще:

#!/usr/bin/perl -w 

$filename = $ARGV[0]; 
open FILE, "<", $filename or die $!; 

while (<FILE>) { 
    if(/^(.*),,/) { 
     $prefix = $_; 
     $prefix =~ s/,//g; 
     $prefix =~ s/\s+//g; 
     next; 
    } 
    s/^,/$prefix,/g; 
    print $_; 
} 

close FILE; 
+0

Не забудьте 'use strict;' предпочитают лексические дескрипторы файлов; почему вы захватываете и не используете захваченную подстроку; '. *' будет соответствовать пустой строке и т. д. –

+0

ОК. Я немного новичок в perl. Спасибо за совет. Я вижу, что твоя ситуация намного проще. Я посмотрю. Еще раз спасибо –

3

Как я указывал с предыдущим вопросом по той же теме, я нахожу Perl быть проще:

#!/usr/bin/perl 

use strict; 
use warnings; 

my $prefix = q{}; 

while (<>) { 
    last unless /\S/; 
    if (/^(.+),,$/) { 
     $prefix = $1; 
     next; 
    } 
    print $prefix, $_; 
} 
+0

понял, что я бы дал ему еще один вариант без «Community Wiki». Еще раз спасибо за указание ошибки. – bsisco

+0

-1: вы считаете, что формат файла CSV прост, но это не –

+1

@Stefano no, все существующие изменения в CSV не просты, но формат, заданный OP. Целью программы является обработка данных, полученных в соответствии с некоторыми спецификациями, а не с произвольными электронными таблицами, создаваемыми пользователями bazillion. Это полностью поддельное понижение. –

0

Вот решение с AWK:

awk -F, '{ if ($1 != "") prefix=$1; else printf "%s%s\n", prefix,$0 }' myfile.csv 
0

Вот полнофункциональный пример, написанный на Perl , который использует новые функции Perl 5.10;

#!/usr/bin/perl 
use strict; 
use warnings; 

use feature qw'switch say'; 

my $append; 

while(<>){ 
    given($_){ 

    when(/^$/){ 
     # handle empty line 
     say STDERR '#'; 
    } 

    # handle lines that start with "#" 
    when(/^\s*[#](.*)/s){ 
     print STDERR '# comment:', $1; 
    } 

    # handle lines that end with two commas 
    when(/(.+),,\s*$/){ 
     $append = $1; 
    } 

    # handle lines that start with a comma 
    when(/^,/){ 
     die unless defined $append; 
     print $append, $_; 
    } 
    } 
} 

Входной

0917,, 
,882-1273,1 
,95F 9475,1 
,276-080,1 

,40K 0080,1 
,275-690A,1 
,TX-2311,3 
# ignore 
# ignore this too 
,TX-3351,4 
,B-07432,1 
,B-6901,1 
,23-753,1 
,02F 4307,1 
,5.1K QBK-ND,1 
,0944-026,1 
,0944-027,1 
,0944-004,1 
,0944-056,1 
,0944-057,1 
,0944-082,1 
,0944-024,1 
,0944-025,1 
,0944-102,4 
,LOR 102,1 
0918,, 
,CJ1085,1 
,1352-152,4 
,DMS3102A-18-,1 
,6-32 KEP,7 
,6-32 X 3/4,4 
,6-32X1/2,4 
,1251-102,8 
,Oct-32,4 
,10-32 SAE,8 

Выход

# 
# comment: ignore 
# comment: ignore this too 
0917,882-1273,1 
0917,95F 9475,1 
0917,276-080,1 
0917,40K 0080,1 
0917,275-690A,1 
0917,TX-2311,3 
0917,TX-3351,4 
0917,B-07432,1 
0917,B-6901,1 
0917,23-753,1 
0917,02F 4307,1 
0917,5.1K QBK-ND,1 
0917,0944-026,1 
0917,0944-027,1 
0917,0944-004,1 
0917,0944-056,1 
0917,0944-057,1 
0917,0944-082,1 
0917,0944-024,1 
0917,0944-025,1 
0917,0944-102,4 
0917,LOR 102,1 
0918,CJ1085,1 
0918,1352-152,4 
0918,DMS3102A-18-,1 
0918,6-32 KEP,7 
0918,6-32 X 3/4,4 
0918,6-32X1/2,4 
0918,1251-102,8 
0918,Oct-32,4 
0918,10-32 SAE,8 
0

Вот СЭД решение. Это не самый чистый, и я уверен, что есть лучший способ транслитерировать две линии, но я нашел это интересным. (В действительности, я бы пошел с решением Perl, но я разместил его для новинки и хотел бы увидеть улучшения.)

 
sed -e '/,,/{s/,,//; h; d;}' -e 'G' -e 's/\(.*\)\n\(.*\)/\2\1/' 
+0

, поскольку файлы CSV имеют четкую структуру данных, например, фиксированные разделители. поэтому будет проще использовать поля, а не регулярное выражение для управления данными. – ghostdog74

+0

@ ghostdog74: это проголосовать за мой ответ? Этот голос должен пойти на вопрос, а не на мой ответ! –

Смежные вопросы