Отформатируйте Поле даты.CSV файла с несколькими запятыми в строковом поле

Вот является миленький прием таким удивленным меня (жизненное средство сохранения при замораживании удаленной системы без МОТ (или KVM). Волшебство ключ SysRq. Если это активно в Вашей системе, я верю удару ALT + SysRq + o должен выключить Вашу систему. Это - трудное завершение работы (если я вспоминаю правильно, не хотят тестировать его прямо сейчас!), таким образом, можно нажать: ALT + SysRq + e (приятно уничтожьте все процессы), ALT + SysRq + i Уничтожьте все остальное), ALT + SysRq + s синхронизируйте все файловые системы, ALT + SysRq + u для перемонтирования разделов как только для чтения затем сделайте b или o комбинацию (перезагрузка или завершение работы)

Так или иначе я не думаю, что это - лучший способ остановить Вашу систему, другие ответы могут более подойти, но вышеупомянутое должно выручить Вас если Ваш застрявший!

2
17.10.2013, 02:40
4 ответа

Вы разделяете на запятых, но затем имеете строки с запятыми. Не думайте, что Вы получаете 9-й столбец как дату. Вставка a print m после того, как эта строка показывает как очень:

m=substr($9,4,3)
print m

Пример

MY M: lum
column1,column2,column3,column4,column5,column6, column7, Column8,00/00/2009, Column10
MY M: me"
"12","B000QRIGJ4","4432","string with quotes, and with a comma, and colon: in between","4432","author1,00/00/2000,"890","88","11-OCT-11","12"
MY M: tho
"4432","B000QRIGJ4","890","another, string with quotes, and with more than, two commas: in between","455",00/00/2002, name","12","455","12-OCT-11","55"
MY M: me"
"11","B000QRIGJ4","77","string with, commas and (paranthesis) and : colans, in between","12","author3,00/00/2000,"333","22","13-OCT-11","232"

Я думаю, что необходимо заново продумать подход немного или выйти из любых запятых, которые включены в строки.

Фиксация

awk имеет странную, но полезную способность разделить на группах символов. Один подход должен был бы разделить на "," вместо просто запятых.

Пример (улучшение № 1)

$ awk -F'","' '
 BEGIN {
 split("JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC", month, " ")
 for (i=1; i<=12; i++) mdigit[month[i]]=i
 }
 {
  if(NR==1){print}
  else{ m=substr($9,4,3); print "MY M: " m;
   $9 = sprintf("%02d/%02d/20%02d",mdigit[m],substr($9,1,2),substr($9,8,20))
  print
 } }' OFS="," file.csv

Вывод

MY M: 
column1,column2,column3,column4,column5,column6, column7, Column8, Column9, Column10,,,,,,,,00/00/2000
MY M: OCT
"12,B000QRIGJ4,4432,string with quotes, and with a comma, and colon: in between,4432,author1, name,890,88,10/11/2011,12"
MY M: OCT
"4432,B000QRIGJ4,890,another, string with quotes, and with more than, two commas: in between,455,author2, name,12,455,10/12/2011,55"
MY M: OCT
"11,B000QRIGJ4,77,string with, commas and (paranthesis) and : colans, in between,12,author3, name,333,22,10/13/2011,232"

Даже это не совершенно правильно. Необходимо будет сделать дополнительную уборку на нем, чтобы вернуть кавычки в и затем удалить дублирующиеся кавычки вначале и конец строк.

Пример (улучшение № 2)

$ awk -F'","' '
 BEGIN {
 split("JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC", month, " ")
 for (i=1; i<=12; i++) mdigit[month[i]]=i
 }
 { m=substr($9,4,3); print "MY M: " m;
 $9 = sprintf("\"%02d/%02d/20%02d\"",mdigit[m],substr($9,1,2),substr($9,8,20))
 for (i=1; i<=10; i++) printf("\"%s\",",$i); printf("%s\n","")
 /\"\"/ }' OFS="," file.csv 

Вывод

MY M: 
"column1,column2,column3,column4,column5,column6, column7, Column8, Column9, Column10","","","","","","","",""00/00/2000"","",
MY M: OCT
""12","B000QRIGJ4","4432","string with quotes, and with a comma, and colon: in between","4432","author1, name","890","88",""10/11/2011"","12"",
MY M: OCT
""4432","B000QRIGJ4","890","another, string with quotes, and with more than, two commas: in between","455","author2, name","12","455",""10/12/2011"","55"",
MY M: OCT
""11","B000QRIGJ4","77","string with, commas and (paranthesis) and : colans, in between","12","author3, name","333","22",""10/13/2011"","232"",

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

Пример (улучшение № 3)

Хорошо, таким образом, я не мог только оставить это, таким образом, вот рабочий пример.

awk -F'","' '
 BEGIN {
 split("JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC", month, " ")
 for (i=1; i<=12; i++) mdigit[month[i]]=i
 }

 { if (NR==1){print; next} }
 { m=substr($9,4,3)
 $9 = sprintf("%02d/%02d/20%02d",mdigit[m],substr($9,1,2),substr($9,8,20))
 for (i=1; i<=10; i++) printf("\"%s\",",$i); printf("%s\n","")
 }' OFS="," file.csv | sed -e 's/""/"/g' -e 's/,$//'

Вывод

column1,column2,column3,column4,column5,column6, column7, Column8, Column9, Column10
"12","B000QRIGJ4","4432","string with quotes, and with a comma, and colon: in between","4432","author1, name","890","88","10/11/2011","12"
"4432","B000QRIGJ4","890","another, string with quotes, and with more than, two commas: in between","455","author2, name","12","455","10/12/2011","55"
"11","B000QRIGJ4","77","string with, commas and (paranthesis) and : colans, in between","12","author3, name","333","22","10/13/2011","232"
4
27.01.2020, 21:49
  • 1
    какая-либо причина печати первой строки с дополнительными полями? как это ","","","","","","","",""00/00/2000"","",? также, я получаю дополнительные кавычки для поля, которое было обработано и также в конце записи как в **,""10/11/2011"","12"",**... Сообщите мне, как зафиксировать это? –  Dhruuv 16.10.2013, 22:25
  • 2
    @Dhruuv - Я делаю попытку к очистке Вашего примера кода 8-). Это вызвано тем, что Вы применяете substr ко всем строкам и не только 2-й строке на, BTW. –  slm♦ 16.10.2013, 22:50
  • 3
    @Dhruuv - посмотрите заключительное обновление, работы теперь. –  slm♦ 16.10.2013, 22:52
  • 4
    Это работает отлично теперь... огромное спасибо за справку и жаль о :) –  Dhruuv 16.10.2013, 23:44

Простой путь

Измените все случаи DD-MMM-YYYY кому: YYYY/MM/DD независимо от того, где они найдены:

$ perl -pe 'BEGIN{ @month=qw(JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC); 
                for ($i=1; $i<=12; $i++) {$mdigit{$month[$i]}=$i;}
               } 
          s#(\d{1,2})-(\w{3})-(\d{2,4})#20$3/$mdigit{$2}/$1#;' foo.csv

column1,column2,column3,column4,column5,column6, column7, Column8, Column9, Column10
"12","B000QRIGJ4","4432","string with quotes, and with a comma, and colon: in between","4432","author1, name","890","88","2011/9/11","12"
"4432","B000QRIGJ4","890","another, string with quotes, and with more than, two commas: in between","455","author2, name","12","455","2011/9/12","55"
"11","B000QRIGJ4","77","string with, commas and (paranthesis) and : colans, in between","12","author3, name","333","22","2011/9/13","232"

Точный путь

Только измените формат если в 9-м поле. Используя perl's -a флаг, который разделяет каждую строку на поля (как awk, но поля $F[0],$F[1]...$F[N-1]) объединенный с -F который устанавливает разделитель полей на "," можно сделать:

perl -F'\",\"' -lane 'BEGIN{
               @month=qw(JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC); 
               for ($i=1; $i<=12; $i++) {$mdigit{$month[$i]}=$i;}
              } 
              $F[8]=~s#(\d{1,2})-(\w{3})-(\d{2,4})#20$3/$mdigit{$2}/$1# if $.>1; 
              print join("\",\"",@F)' foo.csv

Это распечатает YYYY/MM/DD и делает предположение (как Вы делаете в своем вопросе), с которого запускаются все годы 20.

4
27.01.2020, 21:49
  • 1
    я плохо знаком с Linux, не возражайте против меня выяснение... Ваш код печатает первую строку с дополнительными полями? как это""","", "", ",""","", "", ", "00/00/2000""""? также, месяц в выводе не является корректным. Это на самом деле вычитает 1 месяц с входного месяца..., предложите то, что фиксирует, чтобы быть сделанным для кода... –  Dhruuv 16.10.2013, 22:44
  • 2
    @Dhruuv извините, мое плохое, я делал замену относительно первой строки, которая имеет нет ". Попробуйте обновленный код, он должен работать. –  terdon♦ 16.10.2013, 22:56

Используйте инструмент с надлежащим синтаксическим анализатором CSV. Например, с рубином:

ruby -rcsv -pe '
  if $. > 1
    row = CSV.parse_line($_)
    row[8] = Date.parse(row[8]).strftime("%Y/%m/%d")
    $_ = row.to_csv(:force_quotes=>true)
  end
' file.csv
column1,column2,column3,column4,column5,column6, column7, Column8, Column9, Column10
"12","B000QRIGJ4","4432","string with quotes, and with a comma, and colon: in between","4432","author1, name","890","88","2011/10/11","12"
"4432","B000QRIGJ4","890","another, string with quotes, and with more than, two commas: in between","455","author2, name","12","455","2011/10/12","55"
"11","B000QRIGJ4","77","string with, commas and (paranthesis) and : colans, in between","12","author3, name","333","22","2011/10/13","232"
3
27.01.2020, 21:49
  • 1
    Спасибо за быстрый ответ... Я пытался использовать, применяют Ваш код, он дает следующую ошибку... **column1,column2,column3,column4,column5,column6,column7,Column8,Column9,Column10 -e:4: uninitialized constant Date (NameError)**. Какие-либо предложения? –  Dhruuv 16.10.2013, 22:29
  • 2
    Вы, возможно, должны добавить -rdate –  glenn jackman 16.10.2013, 22:32

А-ч, я не знал, что не bash/awk/shell ответы были позволены. Я повторю рекомендации не использовать хакерство оболочки для контакта с CSV. Вот мое решение для жемчуга. Эти единственные модули ядра использования:

#!/usr/bin/perl
# The 9th field
# convert DD-MMM-YY to  YYYY/MM/DD.
# using only perl core modules

use warnings;
use strict;
use diagnostics;

use Text::ParseWords;
use Time::Piece;

my $csvfile = "file.csv";
my $csvfilenew = "file_new.csv";
my $line   = ();
my @fields = ();

open( FILE, "<$csvfile" )
  or die("Couldn't open CSV file $csvfile:$!\\n");
open( OUTFILE, ">>$csvfilenew" )
  or die("Couldn't open new CSV file $csvfilenew:$!\\n");

while ( $line = <FILE> ) {
    my @fields = quotewords( ',', 1, $line );

    if (index($line, "column1") != -1) {
    print "skipping first line - doesn't contain dates to parse!\n";
    next;
    }
# DD-MMM-YY to YYYY/MM/MM
# The strftime man page describes all of the date string variables
    my $date = Time::Piece->strptime($fields[8], '"%e-%b-%y"');
    $fields[8] = $date->strftime('"%Y/%m/%d"');

    print OUTFILE join( ',', @fields );

}
close (FILE);
close (OUTFILE);

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

    my $date = Time::Piece->strptime($fields[8], '%e-%b-%y');
    $fields[8] = $date->strftime('%Y/%m/%d');
1
27.01.2020, 21:49

Теги

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