Rimuovi solo le virgole presenti tra virgolette


10

In un file di testo, voglio rimuovere ,(virgole) e anche "(virgolette) (solo se le virgolette doppie contengono numeri separati da virgole).

56,72,"12,34,54",x,y,"foo,a,b,bar"

Uscita prevista

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

Nota: mostro la riga sopra solo come esempio. Il mio file di testo contiene molte righe come sopra e i numeri separati da virgole presenti tra virgolette doppie dovrebbero variare. Questo è,

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"

Uscita prevista:

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"

C'è un nnumero di numeri presenti tra virgolette separate da virgole. E lascia anche le doppie virgolette che contengono caratteri così come sono.

Adoro lo sedstrumento di elaborazione del testo. Sono felice se pubblichi qualche sedsoluzione per questo.


Da 56,72,"12,34,54",x,y,"foo,a,b,bar"a 56,72,123454,x,y,"a,b", fooed barè scomparire. È l'output desiderato?
cuonglm,

L'esempio che usi è un po 'confuso poiché alcuni elementi (come fooe bar) vengono rimossi insieme alle virgole. Inoltre, alcune delle citazioni scompaiono dove altri rimangono. Per non parlare del fatto che le virgole tra ae brimangono pure. C'è qualche modello in questi?
HalosGhost

modificato mi dispiace amici.
Avinash Raj,

Le tue modifiche non hanno veramente chiarito il tuo esempio. Si prega di vedere il mio ultimo commento .
HalosGhost

rimuovi tutte le virgole tra virgolette doppie e anche le virgolette solo se le virgolette contengono numeri.
Avinash Raj,

Risposte:


7

Questo (adattato da qui ) dovrebbe fare ciò di cui hai bisogno sebbene il Perl di @ rici sia molto più semplice:

$ 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"

Spiegazione

  • :a: definisce un'etichetta chiamata a.
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/ : Questo deve essere suddiviso
    • Prima di tutto, utilizzando questo costrutto: (foo(bar)), \1sarà foobare \2sarà bar.
    • "[0-9,]*",?: corrisponde a 0 o più di 0-9o ,, seguito da 0 o 1 ,.
    • ("[0-9,]*",?)* : corrisponde a 0 o più di quanto sopra.
    • "[0-9,]*: corrisponde a 0 o più di 0-9o ,che arrivano subito dopo a"
  • ta;: torna all'etichetta aed esegui di nuovo se la sostituzione ha avuto successo.
  • s/""/","/g;: post produzione. Sostituisci ""con ",".
  • s/"([0-9]*)",?/\1,/g : rimuove tutte le virgolette attorno ai numeri.

Questo potrebbe essere più facile da capire con un altro esempio:

$ echo '"1,2,3,4"' | sed -nr ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;p;ta;'
"1,2,34"
"1,234"
"1234"
"1234"

Quindi, mentre puoi trovare un numero subito dopo una citazione e seguito da una virgola e un altro numero, unisci i due numeri insieme e ripeti il ​​processo fino a quando non è più possibile.

A questo punto credo sia utile menzionare una citazione info sedche appare nella sezione che descrive funzioni avanzate come l'etichetta usata sopra (grazie per aver scoperto se @Braiam):

Nella maggior parte dei casi, l'uso di questi comandi indica che probabilmente stai meglio programmando in qualcosa come "awk" o Perl.


10

Se perl è OK, ecco un modo breve (e probabilmente veloce, se non necessariamente semplice :)) di farlo:

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

Il eflag per l' s:::operatore (che è solo un altro modo di scrivere s///) fa sì che la sostituzione venga trattata come un'espressione che viene valutata ogni volta. Quell'espressione prende la $1cattura dalla regex (alla quale mancano già le virgolette) e la traduce ( y///, che può anche essere scritta come tr///) eliminando ( /d) tutte le virgole. Il rflag to yè necessario per ottenere il valore come stringa tradotta, anziché il conteggio delle traduzioni.

Per coloro che in qualche modo si sentono imbrattati dal perl, ecco l'equivalente del pitone. Python non è in realtà uno strumento a una linea di shell, ma a volte può essere convinto a collaborare. Quanto segue può essere scritto come una riga (a differenza dei forloop, che non possono essere), ma lo scorrimento orizzontale lo rende (anche più) illeggibile:

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: buono! E usa y///invece di tr///salvarci un altro personaggio.
cuonglm,

6

Per i dati CSV, userei una lingua con un vero parser CSV. Ad esempio con 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"

0

blockquote

Ciao Ecco il codice Python con cui sostituire le virgole tra virgolette doppie, le virgole vengono sostituite con il carattere pipe (|)

Questo codice Python sostituisce le virgole racchiuse tra virgolette doppie

ad esempio: x, y, z, 1,2, "r, e, t, y", h, 8,5,6

se sostituire con Pipe x, y, z, 1,2, "r | e | t | y", h, 8,5,6

se sostituisci con null x, y, z, 1,2, "rety", 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()

piccola spiegazione necessaria.
Mongrel,

Questo codice Python viene utilizzato per sostituire le cose tra virgolette doppie
Vijay Kumar Akarapu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.