Unix: поиск и замена последовательных запятых на последовательные конвейеры

Jan 08 2021

Я конвертирую CSV с двойными кавычками в текстовый файл с разделителями конвейера в Unix. Я использовал следующую команду sed, чтобы заменить "," на | затем удалите начальную и конечную двойные кавычки.

sed -e 's/","/|/g' -e 's/"//g' filenm.csv > filenm.txt

Но в файле, похоже, есть последовательные запятые без двойных кавычек, и они не заменяются.

Col1|col2|col3|col4|col5|col6|col7|col8
Val1|val2|val3,,,,val7|val8

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

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

Я пробовал использовать для этого ниже, но не работал.

sed -e 's/,{1,\}/|{1,\}/g' filenm.csv > filenm.txt

образец CSV-файла, открытого в блокноте:

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

Я надеюсь, что это поможет воспроизвести проблему и решить ее.

Заранее спасибо....

Ответы

2 WiktorStribiżew Jan 08 2021 at 22:37

Вы можете использовать perl:

perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' filenm.csv > filenm.txt

Детали :

  • "([^"]*)"|,- шаблон регулярного выражения, который соответствует ", затем захватывает в Группу 1 любые ноль или более символов, кроме, "а затем соответствует ", или просто совпадает с a ,во всех других контекстах
  • defined($1) ? $1 : "|"- RHS, замена, которая заменяет совпадение либо значением Группы 1 (если была сопоставлена ​​Группа 1), либо |(если ,была сопоставлена)
  • ge- gозначает global(заменяет все вхождения) и eзаставляет Perl обрабатывать RHS как выражение Perl.

Посмотреть онлайн-тест :

#!/bin/bash
s='"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","0","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"'
perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' <<< "$s"

Выход:

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|0|No.38,3rd st, RRR NNN, TRT||||9999999999
4 potong Jan 08 2021 at 23:05

Это может сработать для вас (GNU sed):

sed -E ':a;s/^(("[^",]*",+)*"[^",]*),/\1\n/;ta;y/,\n/|,/' file

Итеративно заменяйте ,'s между "' символами новой строки, затем переводите ,'s для |' s и перевод строки для ,'s.

1 RamanSailopal Jan 09 2021 at 00:35

Использование awk:

awk -F \" '{ for(i=1;i<=NF;i++) { if ($i ~ /^[,]{2,}$/) { $i="," } } OFS="\"";gsub("\",\"","\"|\"",$0)}1' sample.csv

Объяснение:

awk -F \" '{  # Set the field delimiter to double quote
             for(i=1;i<=NF;i++) { 
               if ($i ~ /^[,]{2,}$/) { 
                  $i="," # Loop through each field and if is contains 2 or more commas, set that field to one comma } } OFS="\""; gsub("\",\"","\"|\"",$0) # Substitute "," for "|"
           }1' sample.csv
1 Daweo Jan 09 2021 at 01:50

Я бы использовал AWKдля этого GNU следующим образом. Пусть file.txtсодержание будет

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

тогда

awk 'BEGIN{FS="\"";OFS=""}{for(i=1;i<=NF;i+=2){$i=gensub(/,/,"|","g",$i)};print $0}' file.txt

выход

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|15|No.38,3rd st, RRR NNN, TRT||||9999999999
456|DEF|12/20/2020|||||test-country|9999999999
465|XYZ|||No.38,3rd st, RRR NNN, TRT||||9999999999

Я предполагал, что первый и последний столбец никогда не бывает пустым. Я использую "как разделитель полей, а затем в каждом нечетном поле (только в них ,) я меняю все ,на |. Наконец, я печатаю такую ​​измененную строку целиком.

(проверено в GNU Awk 5.0.1)