quando estou trabalhando com csv, vírgulas indesejadas (',') enganam meu arquivo csv e, como resultado, causam inconsistência.
por favor encontre em detalhes abaixo.
Meu arquivo csv de amostra:
1|a,b|4
1|c,d|4
1|e,f|4
1|g,h|4
1|i,j|4
Quero o resultado final como:
1|"a,b"|4
1|"c,d"|4
1|"e,f"|4
1|"g,h"|4
1|"i,j"|4
Depois de adicionar as aspas, substituirei "|" com "," para que meu csv funcione como eu esperava.
Usei o comando abaixo, mas não está dando conforme o esperado.
sed -e 's/,/"&"/' file1.txt
Responder1
Usando csvformat
decsvkit
, e assumindo que o resultado final deve ser um arquivo CSV com vírgula como delimitador (conforme descrito no texto da pergunta):
$ csvformat -d '|' file
1,"a,b",4
1,"c,d",4
1,"e,f",4
1,"g,h",4
1,"i,j",4
Isso reformata o arquivo CSV de ter |
caracteres como delimitador para ter a vírgula padrão como delimitador. Ao fazer isso, ele cita corretamente os campos que precisam ser citados.
Isso também lida adequadamente com campos com novas linhas incorporadas:
$ cat file
1|a,b|4
1|c,d|4
1|e,f|4
1|g,h|4
1|i,j|4
2|"line 1,
line2"|5
$ csvformat -d '|' file
1,"a,b",4
1,"c,d",4
1,"e,f",4
1,"g,h",4
1,"i,j",4
2,"line 1,
line2",5
Se você tiver um documento em algum formato estruturado, como CSV, JSON, XML, YAML, TOML, etc., não há razãonãopara usar um analisador para esse formato de documento para analisar esse documento.
Responder2
Você poderia fazer:
awk -F'[|]' -v OFS=',' -v q='"' '{ for(i=1; i<=NF; i++) $i=q $i q }1' infile
com -F'[|]'
definimos o separador de campo de entrada.
com -v OFS=','
definimos o separador de campo de saída.
NF
identifica quantos campos existem em cada linha/registro com base no FS (separador de campos de entrada), então fazemos um loop sobre o número de campos e adicionamos aspas duplas para cada um deles e imprimimos a atualização final na linha com1
idioma do awkpara a impressão.
observe que todos os campos estão sendo citados com este comando, o que obviamente não é um problema por ter um arquivo CSV válido.
Responder3
Com sed
:
$ sed 's/[^|]*,[^|]*/"&"/g; y/|/,/' ip.txt
1,"a,b",4
1,"c,d",4
1,"e,f",4
1,"g,h",4
1,"i,j",4
s/[^|]*,[^|]*/"&"/g
adicione aspas duplas a todos os campos que contêm,
y/|/,/
mude todos os|
caracteres para,
Com perl
:
perl -F'\|' -lane 'print join ",", map {/,/ ? qq("$_") : $_} @F'
Isso é usado |
como separador de campo de entrada. Em seguida, map
adicionaremos aspas duplas para todos os campos que contenham ,
. Finalmente, join
é usado para combinar os campos com ,
caracteres.
Responder4
Outra sed
maneira:
sed 's;\([^|]*\)|\([^|]*\)|\(.*\)$;\1,"\2",\3;' data
Ou se você sed
suporta o carregamento de ERE
, como GNU sed
, você pode evitar todo o trabalho de escape:
sed -E 's;([^|]+)\|([^|]+)\|(.+)$;\1,"\2",\3;' data
Você pode explorar o fato de que apenas o grupo do meio é delimitado por um |
em cada limite e torná-lo sed
ainda mais curto:
sed 's;|\([^|]*\)|;,"\1",;' data
Claro que também aqui, se o seu suporte sed -E
você pode carregar ERE
e evitar um tedioso trabalho de fuga