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

У меня есть файл .CSV (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","11-OCT-11","12" "4432","B000QRIGJ4","890","another, string with quotes, and with more than, two commas: in between","455","author2, name","12","455","12-OCT-11","55" "11","B000QRIGJ4","77","string with, commas and (paranthesis) and : colans, in between","12","author3, name","333","22","13-OCT-11","232" 

9-е поле – это поле даты в формате «DD-MMM-YY» . Мне нужно преобразовать его в формат YYYY / MM / DD . Я пытаюсь использовать приведенный ниже код, но бесполезно.

 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) $9 = sprintf("%02d/%02d/"20"%02d",mdigit[m],substr($9,1,2),substr($9,8,20)) print }' OFS="," file.csv > temp_file.csv 

Вывод из файла temp_file.csv после выполнения вышеуказанного кода показан ниже.

 column1,column2,column3,column4,column5,column6,column7,Column8,00/00/2000,Column10 "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" "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" "11","B000QRIGJ4","77","string with, commas and (paranthesis) and : colans, in between","12","author3,00/00/2000,"333","22","13-OCT-11","232" 

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

1) Имеет ли значение двойное цитирование всех значений во всех полях? Если они имеют какое-либо значение, как мне избавиться от них из всех значений, кроме строк с запятыми в них? 2) Любые изменения в моем коде, чтобы я мог отформатировать 9-ое поле, которое в формате «DD-MMM-YYYY» до YYYY / MM / DD

  • Вычисление среднего значения в awk на основе состояния столбца в csv
  • Как извлечь имя столбца (заголовок) из файла CSV, который содержит максимальное значение в строке?
  • Создайте таблицу ASCII art из табличных данных
  • Выберите строки из текстового файла с идентификаторами, указанными в другом файле
  • Как изменить% Hh% M на% M в R CSV?
  • awk, когда оба разделителя и кавычки используются для поля
  • Найти все файлы, создать CSV с одной строкой для каждого подкаталога и имена файлов в столбцах
  • Преобразовать ключ = значения в CSV
  • 4 Solutions collect form web for “Отформатируйте поле Date файла .CSV с несколькими запятыми в поле строки”

    Вы разделяете запятую, но затем имеете строки с запятыми. Не думайте, что вы получаете девятую колонку в качестве даты. Вставка 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" 

    Простой способ

    Измените все вхождения 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-ом поле. Используя флаг -a perl, который разбивает каждую строку на поля (например, 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 .

    Используйте инструмент с правильным парсером CSV. Например, с ruby:

     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" 

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

     #!/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'); 
    Linux и Unix - лучшая ОС в мире.