Supprimer uniquement les virgules présentes dans les guillemets doubles

10

Dans un fichier texte, je veux supprimer ,(virgules) et aussi les "(guillemets) (uniquement si les guillemets doubles contiennent des nombres séparés par des virgules).

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

Sortie attendue

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

Remarque: je montre la ligne ci-dessus à titre d'exemple. Mon fichier texte contient de nombreuses lignes comme ci-dessus et les nombres séparés par des virgules présents dans les guillemets doubles doivent varier. C'est,

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"

Production attendue:

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"

Il y a un ncertain nombre de nombres dans les guillemets séparés par des virgules. Et laissez également les guillemets doubles qui contiennent les caractères tels quels.

J'adore l' sedoutil de traitement de texte. Je suis heureux si vous postez une sedsolution pour cela.

Avinash Raj
la source
De 56,72,"12,34,54",x,y,"foo,a,b,bar"à 56,72,123454,x,y,"a,b", fooet bardisparaît. Est-ce la sortie souhaitée?
cuonglm
L'exemple que vous utilisez est un peu déroutant car certains éléments (comme fooet bar) sont supprimés avec les virgules. De plus, certaines des citations disparaissent là où d'autres restent. Sans oublier que les virgules entre aet brestent aussi. Y a-t-il une tendance à cela?
HalosGhost
amis désolés modifiés.
Avinash Raj
Vos modifications n'ont pas vraiment clarifié votre exemple. Veuillez voir mon dernier commentaire .
HalosGhost
supprimez toutes les virgules entre guillemets doubles et les guillemets uniquement si les guillemets contiennent des nombres.
Avinash Raj

Réponses:

7

Ceci (adapté d' ici ) devrait faire ce dont vous avez besoin, bien que celui de @ rici Perl soit beaucoup plus simple:

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

Explication

  • :a: définir une étiquette appelée a.
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/ : Celui-ci doit être décomposé
    • Tout d' abord, en utilisant cette construction: (foo(bar)), \1sera foobaret \2sera bar.
    • "[0-9,]*",?: correspond à 0 ou plus de 0-9ou ,, suivi de 0 ou 1 ,.
    • ("[0-9,]*",?)* : correspond à 0 ou plus de ce qui précède.
    • "[0-9,]*: correspond à 0 ou plus 0-9ou ,juste après un"
  • ta;: revenir à l'étiquette aet recommencer si la substitution a réussi.
  • s/""/","/g;: post-traitement. Remplacez ""par ",".
  • s/"([0-9]*)",?/\1,/g : supprime toutes les citations autour des nombres.

Cela pourrait être plus facile à comprendre avec un autre exemple:

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

Ainsi, bien que vous puissiez trouver un numéro juste après un devis et suivi d'une virgule et d'un autre numéro, joignez les deux chiffres ensemble et répétez le processus jusqu'à ce qu'il ne soit plus possible.

À ce stade, je pense qu'il est utile de mentionner une citation info sedqui apparaît dans la section décrivant les fonctions avancées telles que l'étiquette utilisée ci-dessus (merci d'avoir trouvé si @Braiam):

Dans la plupart des cas, l'utilisation de ces commandes indique que vous feriez probablement mieux de programmer dans quelque chose comme `awk 'ou Perl.

terdon
la source
10

Si perl est OK, voici une manière courte (et probablement rapide, sinon nécessairement simple :)):

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

Le edrapeau de l' s:::opérateur (qui n'est qu'une autre façon d'écrire s///) fait que le remplacement est traité comme une expression qui est évaluée à chaque fois. Cette expression prend la $1capture de l'expression régulière (qui manque déjà les guillemets) et la traduit ( y///, qui peut également s'écrire tr///) en supprimant ( /d) toutes les virgules. L' rindicateur to yest nécessaire pour que la valeur soit la chaîne traduite, au lieu du nombre de traductions.

Pour ceux qui se sentent en quelque sorte souillés par perl, voici l'équivalent python. Python n'est vraiment pas un outil shell one-liner, mais parfois il peut être cajolé en coopération. Les éléments suivants peuvent être écrits sur une seule ligne (contrairement aux forboucles, qui ne peuvent pas l'être), mais le défilement horizontal la rend (encore plus) illisible:

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
la source
@rici: Bien! Et utilisez y///au lieu de tr///nous sauver un caractère de plus.
cuonglm
6

Pour les données CSV, j'utiliserais un langage avec un véritable analyseur CSV. Par exemple avec 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
la source
0

Blockquote

Salut Voici le code Python pour remplacer les virgules par des guillemets doubles, les virgules sont remplacées par le caractère pipe (|)

Ce code Python remplace les virgules entre guillemets

par exemple: x, y, z, 1,2, "r, e, t, y", h, 8,5,6

si remplacer par Tuyau x, y, z, 1,2, "r | e | t | y", h, 8,5,6

si remplacer par 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()
Vijay Kumar Akarapu
la source
peu d'explications nécessaires.
Mongrel
Ce code python est utilisé pour remplacer les choses entre guillemets doubles
Vijay Kumar Akarapu