Eu tenho um arquivo de entrada delimitado por vírgulas ( ,
). Existem alguns campos entre aspas duplas que possuem vírgula. Aqui está a linha de amostra
123,"ABC, DEV 23",345,534.202,NAME
Eu preciso remover todas as vírgulas que ocorrem dentro das aspas duplas e aspas duplas também. Portanto, a linha acima deve ser analisada conforme mostrado abaixo
123,ABC DEV 23,345,534.202,NAME
Eu tentei o seguinte usando, sed
mas não dando os resultados esperados.
sed -e 's/\(".*\),\(".*\)/\1 \2/g'
Algum truque rápido com sed
, awk
ou qualquer outro utilitário unix, por favor?
text-processing
sed
awk
csv
mtk
fonte
fonte
Respostas:
Se as aspas estiverem equilibradas, você deverá remover vírgulas entre todas as outras aspas, isso pode ser expresso da
awk
seguinte maneira:Saída:
Explicação
O
-F"
makes awk separa a linha nos sinais de aspas duplas, o que significa que todos os outros campos serão o texto entre aspas. O loop for é executadogsub
, abreviação de substituto global, em todos os outros campos, substituindo vírgula (","
) por nada (""
). A1
no final invoca o código-padrão do bloco:{ print $0 }
.fonte
gsub
e explicar resumidamente, como esse liner funciona? por favor.{ print $0 }
. Eu adicionei isso à explicação também.prefix,"something,otherthing[newline]something , else[newline]3rdline,and,things",suffix
(ou seja: várias linhas e aninhado "," em qualquer lugar dentro de aspas duplas de várias linhas: a"...."
parte inteira deve ser reconectada e a parte interna,
deve ser substituído / removido ...): seu script não verá pares de aspas duplas nesse caso, e não é realmente fácil de resolver (é necessário "juntar novamente" as linhas que estão em um "aberto" (ou seja, com números ímpares) aspas duplas ... + tomar cuidado extra se houver também um escapou\"
dentro da string)awk -F'"' -v OFS='"' '{ for (I=1; i<=NF; i+=2) gsub(",", "|", $i) } 1' infile
Existe uma boa resposta, usando sed simplesmente uma vez com um loop :
Explicação:
:a;
é um rótulo para ramo mais furters/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /
pode conter 3 partes fechadas[^"]*,\?\|"[^",]*",\?
corresponde a uma sequência que não contém aspas duplas, talvez seguida por um coma ou por uma delimitada por duas aspas duplas, sem coma e talvez seguida por um coma.ta
fará um loop para:a
se os/
comando anterior fez alguma alteração.fonte
Uma solução geral que também pode manipular várias vírgulas entre aspas balanceadas precisa de uma substituição aninhada. Eu implementei uma solução em perl, que processa todas as linhas de uma determinada entrada e substitui vírgulas em todos os outros pares de aspas:
ou em suma
Você pode canalizar o texto que deseja processar para o comando ou especificar o arquivo de texto a ser processado como o último argumento da linha de comandos.
fonte
[^\\]
efeito indesejável de combinar o último caractere entre aspas e removê-lo (não \ caractere), ou seja, você não deve consumir esse caractere. Tente em(?<!\\)
vez disso.[^"]*
para fazer a correspondência não-gananciosos (ou seja combina com tudo a partir de um"
para o seguinte"
):perl -pe 's/"([^"]+)"/($match = $1) =~ (s:,::g);$match;/ge;'
. Ele não reconhece a ideia bizarra que uma citação pode ser precedidos por uma barra invertida :-)[^"]*
abordagem ou a abordagem explícita não gananciosa consumisse menos tempo de CPU.Eu usaria um idioma com um analisador CSV adequado. Por exemplo:
fonte
Suas segundas citações estão fora de lugar:
Além disso, o uso de expressões regulares tende a corresponder à parte mais longa possível do texto, o que significa que isso não funcionará se você tiver mais de um campo entre aspas na sequência.
Uma maneira de lidar com vários campos citados no sed
Essa também é uma maneira de resolver isso, no entanto, com entradas que podem conter mais de uma vírgula por campo citado, a primeira expressão no sed precisaria ser repetida tantas vezes quanto o conteúdo máximo de vírgula em um único campo ou até que não altera a saída.
A execução de sed com mais de uma expressão deve ser mais eficiente do que vários processos sed em execução e um "tr" em execução com tubos abertos.
No entanto, isso pode ter consequências indesejadas se a entrada não estiver formatada corretamente. ou seja, aspas aninhadas, aspas não terminadas.
Usando o exemplo em execução:
Saída:
fonte
sed -r ':r; s/("[^",]+),([^",]*)/\1 \2/g; tr; s/"//g'
.No perl - você pode usar
Text::CSV
para analisar isso e fazê-lo trivialmente:Você pode imprimir com
Text::CSV
mas tende a preservar aspas, se o fizer. (Embora, eu sugiro - em vez de retirar aspas para sua saída, você pode simplesmente analisar usandoText::CSV
em primeiro lugar).fonte
Eu criei uma função para percorrer todos os caracteres da string.
Se o caractere for uma cotação, a verificação (b_in_qt) será marcada como verdadeira.
Enquanto b_in_qt for verdadeiro, todas as vírgulas são substituídas por um espaço.
b_in_qt é definido como false quando a próxima vírgula é encontrada.
fonte