Remover vírgula fora de citações

3

Eu tenho um arquivo de entrada delimitado por vírgulas ( , ). Existem alguns campos entre aspas duplas que contêm uma vírgula. Aqui está a linha de amostra

123,"ABC, DEV 23",345,534.202,NAME

Eu preciso remover todas as vírgulas que não estão ocorrendo entre aspas duplas por ~ Então a saída deve ser como:

123~"ABC, DEV 23"~345~534.202~NAME

Eu tentei isso, mas isso me dá saída reversa:

awk -F '"' -v OFS='' '{ for (i=0; i<= NF; ++i) gsub(",","~",$i) } 1' test.txt
123,ABC~ DEV 23,345,534.202,NAME
    
por Sudeep Adhya 07.02.2018 / 13:34

7 respostas

5

Você basicamente tem um arquivo CSV no qual gostaria de substituir o delimitador, de , a ~ .

Usando csvkit :

$ csvformat -D '~' file.csv >newfile.csv

$ cat newfile.csv
123~ABC, DEV 23~345~534.202~NAME

cvsformat remove as aspas que não são necessárias. Para adicionar aspas:

$ csvformat -U 1 -D '~' file.csv
"123"~"ABC, DEV 23"~"345"~"534.202"~"NAME"

Veja csvformat --help para informações de uso.

    
por 07.02.2018 / 13:52
2
Solução

GNU awk :

awk -v FPAT='[^,]+|"[^"]+"' '{ for(i=1;i<=NF;i++) printf "%s%s",$i,(i<NF? "~" : ORS) }' file
  • FPAT='[^,]+|"[^"]+"' - padrão regex descrevendo cada campo é “qualquer coisa que não seja uma vírgula”, ou “uma aspa dupla, qualquer coisa que não seja aspas duplas e uma aspa dupla de fechamento. ”

A saída:

123~"ABC, DEV 23"~345~534.202~NAME
    
por 07.02.2018 / 14:03
0

Eu fiz abaixo dos 2 métodos para o exemplo acima. Testado

Método1

for (( i=1;i<6;i++)); do awk -F "," -v i="$i" '$i ~ /"/{gsub(" ",",",$2);print }' inputfile;done| tail -1| sed 's/,/~/3g'| sed 's/,/~/1'

saída

123~"ABC, DEV 23"~345~534.202~NAME'

Método2

 sed "s/,/~/3g" inputfile| sed 's/,/~/1'

Saída

123~"ABC, DEV 23"~345~534.202~NAME'
    
por 07.02.2018 / 17:46
0

Você pode tentar este awk

awk 'NR%2==1{gsub(",","~")}1' RS='"' ORS='"' infile
    
por 07.02.2018 / 21:54
0

Caso você não queira instalar um pacote especial, você pode provavelmente o analisador csv de um ruby pré-instalado:

ruby -e 'require "csv"; CSV.filter(output_col_sep: "~") {}'

Exemplos:

1,"2,3"

resulta em

1~2,3

e

1,"
2,3
",4

resulta em

1~"
2,3
"~4
    
por 08.02.2018 / 18:45
0

Isso é o oposto de esta questão que eu também tinha respondido lá, pode ser feito iniciando o valor da etapa do loop a partir de 1.

awk -F\" '{for (i=1;i<=NF;i+=2)gsub(",","~",$i)}1' OFS=\" infile

A saída é:

123~"ABC, DEV 23"~345~534.202~NAME
    
por 07.02.2018 / 18:09
0
awk '{sub(/,/,"~")gsub(/,/,"~",$3)}1' file

output
123~"ABC, DEV 23"~345~534.202~NAME

A primeira vírgula é substituída por sub e o resto por gsub no terceiro campo.

    
por 23.02.2018 / 04:14