Em um arquivo de texto, quero remover ,
(vírgulas) e também as "
(aspas) (somente se as aspas duplas contiverem números separados por vírgulas).
56,72,"12,34,54",x,y,"foo,a,b,bar"
Resultado esperado
56,72,123454,x,y,"foo,a,b,bar"
Observação:Mostro a linha acima apenas como exemplo. Meu arquivo de texto contém muitas linhas como acima e os números separados por vírgulas presentes entre aspas duplas devem variar. Aquilo é,
56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"
Resultado esperado:
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"
Há n
vários números presentes entre aspas duplas separados por vírgulas. E também deixe as aspas duplas que contêm caracteres como estão.
Eu adoro sed
ferramenta de processamento de texto. Fico feliz se você postar alguma sed
solução para isso.
Responder1
Se perl estiver OK, aqui está uma maneira curta (e provavelmente rápida, se não necessariamente simples :)) de fazer isso:
perl -pe 's:"(\d[\d,]+)":$1=~y/,//dr:eg' file
O e
sinalizador para o s:::
operador (que é apenas outra forma de escrever s///
) faz com que a substituição seja tratada como uma expressão que é avaliada todas as vezes. Essa expressão pega a $1
captura da regex (que já está sem as aspas) e a traduz ( y///
, que também pode ser escrita como tr///
) excluindo ( /d
) todas as vírgulas. O r
sinalizador to y
é necessário para que o valor seja a string traduzida, em vez da contagem de traduções.
Para aqueles que de alguma forma se sentem manchados pelo perl, aqui está o equivalente em python. Python não é realmente uma ferramenta shell de uma linha, mas às vezes pode ser persuadido a cooperar. O seguinte pode ser escrito como uma linha (ao contrário for
dos loops, que não podem ser), mas a rolagem horizontal torna-o (ainda mais) ilegível:
python -c '
import re;
import sys;
r=re.compile("\"(\d+(,\d+)*)\"");
all(not sys.stdout.write(r.sub(lambda m:m.group(1).replace(",",""),l))
for l in sys.stdin)
' < file
Responder2
Isto (adaptado deaqui) deve fazer o que você precisa, embora o Perl do @rici seja muito mais simples:
$ sed -r ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;ta; s/""/","/g;
s/"([0-9]*)",?/\1,/g ' file
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454,
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"
Explicação
:a
: defina um rótulo chamadoa
.s/(("[0-9,]*",?)*"[0-9,]*),/\1/
: Este precisa ser dividido- Em primeiro lugar, usando esta construção :
(foo(bar))
,\1
seráfoobar
e\2
serábar
. "[0-9,]*",?
: corresponde a 0 ou mais de0-9
ou,
, seguido por 0 ou 1,
.("[0-9,]*",?)*
: corresponde a 0 ou mais dos itens acima."[0-9,]*
: corresponde a 0 ou mais de0-9
ou,
que vem logo após um"
- Em primeiro lugar, usando esta construção :
ta;
: volte para o rótuloa
e execute novamentesea substituição foi bem sucedida.s/""/","/g;
: pós-processamento. Substituir""
com","
.s/"([0-9]*)",?/\1,/g
: remova todas as aspas em torno dos números.
Isso pode ser mais fácil de entender com outro exemplo:
$ echo '"1,2,3,4"' | sed -nr ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;p;ta;'
"1,2,34"
"1,234"
"1234"
"1234"
Portanto, embora você possa encontrar um número logo após uma aspa e seguido de uma vírgula e outro número, junte os dois números e repita o processo até que não seja mais possível.
Neste ponto, acredito que seja útil mencionar uma citação que info sed
aparece na seção que descreve funções avançadas, como o rótulo usado acima (obrigado por encontrar if @Braiam):
Na maioria dos casos, o uso desses comandos indica que provavelmente será melhor programar em algo como `awk' ou Perl.
Responder3
Para dados CSV, eu usaria uma linguagem com um analisador CSV real. Por exemplo com Ruby:
ruby -rcsv -pe '
row = CSV::parse_line($_).map {|e| e.delete!(",") if e =~ /^[\d,]+$/; e}
$_ = CSV::generate_line(row)
' <<END
56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"
END
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"
Responder4
UsandoRaku(anteriormente conhecido como Perl_6)
~$ raku -pe 's:g/ \" ~ \" (\d+) ** 2..* % "," /{$0.join}/;' file
Entrada de amostra:
56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"
Saída de amostra:
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"
Raku é uma linguagem de programação da família Perl com vários recursos regex poderosos. Veja o URL abaixo para uma visão geral desta resposta:
https://unix.stackexchange.com/a/722570/227738
No código acima, os dígitos são reconhecidos e as vírgulas incorporadas são removidas. A regex aproveita o fato de queestruturas aninhadaspode ser denotado com a nova notação ~ til (aninhada) de Raku, que \" ~ \" [\d+]
significa "um ou mais dígito(s) cercado(s) por "aspas duplas".
Adicionalmente,estruturas repetidaspode ser denotado com o novo quantificador modificado de Raku %
para estruturas repetidas. A notação [\d+] ** 2..* % "," significa "um ou mais dígitos separados por ,
vírgulas com este padrão repetido ** 2..*
duas ou mais vezes. [Se houver um separador final (por exemplo vírgula), use a %%
em vez de %
na sintaxe].
Isto é só o começo. Arquivos CSV com separadores alternativos, novas linhas incorporadas, vírgulas incorporadas, campos potencialmente em branco, etc., realmente precisam ser tratados por um verdadeiro analisador CSV como o Text::CSV
módulo de Raku. Veja os links abaixo para obter detalhes.
https://docs.raku.org/linguagem/regexes
https://raku.land/github:Tux/Text::CSV
https://raku.org