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.


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.


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

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()

peu d'explications nécessaires.
Mongrel

Ce code python est utilisé pour remplacer les choses entre guillemets doubles
Vijay Kumar Akarapu
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.