2015-06-01 4 views
0

У меня есть данные, как это:Заменить символы в определенных столбцах только (CSV)

1;2015-04-10;23:10:00;10.4.2015 23:10;8.9;1007.5;0.3;0.0;0;55 
2;2015-04-10;23:20:00;10.4.2015 23:20;8.6;1007.8;0.4;0.0;0;56 
3;2015-04-10;23:30:00;10.4.2015 23:30;8.5;1008.1;0.4;0.0;0;57 

имеет точку . в виде десятичного разделителя, но мне нужно использовать вместо ,.

Желаемая данные:

1;2015-04-10;23:10:00;10.4.2015 23:10;8,9;1007,5;0,3;0,0;0;55 

Я попытался с помощью Sed. С sed -i 's/\./,/g' myfile.csv я мог бы заменить все точки запятыми, но уничтожил даты в четвертом столбце. Как изменить точки на запятые в другом месте, но оставить четвертый столбец как есть? Если какой-либо другой инструмент Linux лучше для этой задачи, чем Sed, я мог бы использовать его.

ответ

4

СЭД для простых замен, для чего-то просто использовать AWK:

$ awk 'BEGIN{FS=OFS=";"} {for (i=5;i<=NF;i++) sub(/\./,",",$i)} 1' file 
1;2015-04-10;23:10:00;10.4.2015 23:10;8,9;1007,5;0,3;0,0;0;55 
2;2015-04-10;23:20:00;10.4.2015 23:20;8,6;1007,8;0,4;0,0;0;56 
3;2015-04-10;23:30:00;10.4.2015 23:30;8,5;1008,1;0,4;0,0;0;57 
+1

Это работает. Не могли бы вы дать краткое объяснение того, как именно это работает? Я хотел бы понять, как это работает, и синтаксис выглядит довольно сложно. –

+0

Sure - 'BEGIN {FS = OFS ="; "}' = установить разделитель полей в ';'. '{for (i = 5; i <= NF; i ++) sub (/\./,",",$ i)}' = начиная с 5-го поля, заменяйте каждое '.' '' 'в каждом поле , '1' = вызвать действие defaulkt для печати текущей строки. Awk имеет менее 10 фундаментальных (важных, но очень простых) вещей, чтобы понять, а затем остальное - просто урезанный, упрощенный синтаксис типа C, ориентированный на манипулирование текстом. Получить книгу Эффективное программирование Awk, 4-е издание, Арнольд Роббинс. –

+1

Спасибо, теперь это выглядит более ясным. Думаю, мне будет полезно изучить этот инструмент больше. –

0

Perl и Text::CSV:

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

use Text::CSV; 

my $csv = 'Text::CSV'->new({ binary  => 1, 
          sep_char => ';', 
          quote_space => 0, 
          }) or die 'Text::CSV'->error_diag; 
open my $FH, '<:encoding(utf8)', 'input.csv' or die $!; 
$csv->eol("\n"); 
while (my $row = $csv->getline($FH)) { 
    s/\./,/g for @$row[ 0 .. 2, 4 .. $#$row ]; 
    $csv->print(*STDOUT, $row); 
} 
0

Вы могли бы пойти с:

awk 'BEGIN {FS=OFS=";"} {if(NF==5);gsub(/\./,",",$5)} 1 ' filename 

Здесь я использовано gsub вместо sub; разница в том, что sub заменит только первое вхождение, тогда как gsub заменит все вхождения.

0

изменения точки, чтобы запятой во втором столбце

awk '{gsub(/\./,",",$2)}1' file 

1;2015-04-10;23:10:00;10.4.2015 23:10;8,9;1007,5;0,3;0,0;0;55 
2;2015-04-10;23:20:00;10.4.2015 23:20;8,6;1007,8;0,4;0,0;0;56 
3;2015-04-10;23:30:00;10.4.2015 23:30;8,5;1008,1;0,4;0,0;0;57 
Смежные вопросы