Remova apenas as vírgulas presentes entre aspas duplas

10

Em um arquivo de texto, desejo 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"

Saída esperada

56,72,123454,x,y,"foo,a,b,bar"

Nota: Eu 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. Isso é,

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 esperada:

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"

Existem nvá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 amo a sedferramenta de processamento de texto. Fico feliz se você postar alguma sedsolução para isso.

Avinash Raj
fonte
De 56,72,"12,34,54",x,y,"foo,a,b,bar"para 56,72,123454,x,y,"a,b", fooe baré desaparecer. É o resultado desejado?
cuonglm
O exemplo que você usa é um pouco confuso, pois alguns elementos (como fooe bar) são removidos junto com as vírgulas. Além disso, algumas citações desaparecem onde outras permanecem. Sem mencionar que as vírgulas entre ae bpermanecem também. Existe algum padrão para isso?
HalosGhost
editado desculpe amigos.
Avinash Raj
Suas edições não esclareceram genuinamente o seu exemplo. Por favor, veja meu último comentário .
HalosGhost
remova todas as vírgulas entre aspas duplas e também as aspas somente se as aspas contiverem números.
Avinash Raj

Respostas:

7

Isso (adaptado daqui ) deve fazer o que você precisa, embora o Perl one 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: define um rótulo chamado a.
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/ : Este precisa ser dividido
    • Em primeiro lugar, utilizando esta construção: (foo(bar)), \1será foobare \2será bar.
    • "[0-9,]*",?: corresponde a 0 ou mais de 0-9ou ,, seguido por 0 ou 1 ,.
    • ("[0-9,]*",?)* : corresponde a 0 ou mais dos itens acima.
    • "[0-9,]*: corresponde a 0 ou mais 0-9ou ,que vem logo após um"
  • ta;: volte ao rótulo ae execute novamente se a substituição tiver sido bem-sucedida.
  • s/""/","/g;: pós-processamento. Substitua ""por ",".
  • s/"([0-9]*)",?/\1,/g : remova todas as aspas ao redor 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, enquanto você pode encontrar um número logo após uma citação e seguido por 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 info sedque aparece na seção que descreve funções avançadas, como o rótulo usado acima (obrigado por descobrir se @Braiam):

Na maioria dos casos, o uso desses comandos indica que você provavelmente está melhor programando algo como `awk 'ou Perl.

terdon
fonte
10

Se perl estiver OK, eis uma maneira curta (e provavelmente rápida, se não necessariamente simples :) de fazê-lo:

perl -pe 's:"(\d[\d,]+)":$1=~y/,//dr:eg' file

O esinalizador para o s:::operador (que é apenas outra maneira 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 $1captura do regex (que já está faltando as aspas) e a traduz ( y///que também pode ser escrita como tr///) excluindo ( /d) todas as vírgulas. O rsinalizador para yé necessário para que o valor seja a sequência traduzida, em vez da contagem de traduções.

Para aqueles que de alguma forma se sentem manchados por perl, aqui está o equivalente em python. O Python não é realmente uma ferramenta one-liner shell, mas às vezes pode ser convencido a cooperar. O seguinte pode ser escrito como uma linha (diferente dos forloops, que não podem ser), mas a rolagem horizontal torna (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
rici
fonte
@rici: Boa! E use em y///vez de tr///nos salvar mais um personagem.
cuonglm
6

Para dados CSV, eu usaria um idioma 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"
Glenn Jackman
fonte
0

Bloco de citação

Olá, aqui está o código Python para substituir vírgulas entre aspas duplas, vírgulas são substituídas pelo caractere pipe (|)

Este código Python deve substituir vírgulas entre aspas duplas

por exemplo: x, y, z, 1,2, "r, e, t, y", h, 8,5,6

se substituir pelo tubo x, y, z, 1,2, "r | e | t | y", h, 8,5,6

se substituir por nulo x, y, z, 1,2, "tentar novamente", h, 8,5,6

writingFile = open('FileToWrite', 'w')
with open('FileToRead') as f:

    while True:

        c = f.read(1)
        if not c:
            print ("End of file")
            break
        print ("Read a character:", c)


        if c=='"':
            writingFile.write(c) 
            c = f.read(1)
            while c != '"':
                if c== ',':
                    c= '|'
                writingFile.write(c)
                c = f.read(1)


        writingFile.write(c)


writingFile.close()
Vijay Kumar Akarapu
fonte
pouca explicação necessária.
quer
Este código Python é usar para substituir as coisas entre aspas
Vijay Kumar Akarapu