Elimine solo las comas presentes entre comillas dobles

10

En un archivo de texto, quiero eliminar ,(comas) y también las "(comillas) (solo si las comillas dobles contienen números separados por comas).

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

Salida esperada

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

Nota: muestro la línea anterior solo como un ejemplo. Mi archivo de texto contiene muchas líneas como las anteriores y los números separados por comas presentes dentro de las comillas dobles deben variar. Es decir,

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"

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

Hay una ncantidad de números presentes dentro de las comillas dobles separadas por comas. Y también deje las comillas dobles que contienen caracteres tal como están.

Me encanta la sedherramienta de procesamiento de texto. Estoy feliz si publicas alguna sedsolución para esto.

Avinash Raj
fuente
De 56,72,"12,34,54",x,y,"foo,a,b,bar"a 56,72,123454,x,y,"a,b", fooy bares desaparecer. ¿Es tu salida deseada?
Cuonglm
El ejemplo que usa es un poco confuso ya que algunos elementos (como fooy bar) se eliminan junto con las comas. Además, algunas de las citas desaparecen donde quedan otras. Sin mencionar que las comas entre ay bpermanecen también. ¿Hay algún patrón para estos?
HalosGhost
editado lo siento amigos.
Avinash Raj
Sus ediciones no han aclarado genuinamente su ejemplo. Por favor vea mi último comentario .
HalosGhost
elimine todas las comas dentro de comillas dobles y también las comillas solo si las comillas contienen números.
Avinash Raj

Respuestas:

7

Esto (adaptado de aquí ) debería hacer lo que necesita, aunque el Perl de @ rici es mucho más 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"

Explicación

  • :a: define una etiqueta llamada a.
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/ : Este necesita ser desglosado
    • En primer lugar, el uso de este constructo: (foo(bar)), \1será foobary \2será bar.
    • "[0-9,]*",?: coincide con 0 o más de 0-9o ,, seguido de 0 o 1 ,.
    • ("[0-9,]*",?)* : coincide con 0 o más de los anteriores.
    • "[0-9,]*: coincide con 0 o más 0-9o ,que vienen justo después de un"
  • ta;: vuelva a la etiqueta ay vuelva a ejecutar si la sustitución se realizó correctamente.
  • s/""/","/g;: Postprocesamiento. Reemplazar ""con ",".
  • s/"([0-9]*)",?/\1,/g : elimina todas las comillas alrededor de los números.

Esto podría ser más fácil de entender con otro ejemplo:

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

Entonces, si bien puede encontrar un número justo después de una cita y seguido de una coma y otro número, una los dos números y repita el proceso hasta que ya no sea posible.

En este punto, creo que es útil mencionar una cita info sedque aparece en la sección que describe funciones avanzadas como la etiqueta utilizada anteriormente (gracias por encontrar si @Braiam):

En la mayoría de los casos, el uso de estos comandos indica que probablemente sea mejor programar en algo como 'awk' o Perl.

terdon
fuente
10

Si perl está bien, aquí hay una forma corta (y probablemente rápida, si no necesariamente simple :)) de hacerlo:

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

El eindicador del s:::operador (que es solo otra forma de escritura s///) hace que el reemplazo se trate como una expresión que se evalúa cada vez. Esa expresión toma la $1captura de la expresión regular (que ya falta las comillas) y la traduce ( y///que también se puede escribir como tr///) eliminando ( /d) todas las comas. El rindicador a yes necesario para obtener el valor de ser la cadena traducida, en lugar del recuento de traducciones.

Para aquellos que de alguna manera se sienten manchados por Perl, aquí está el equivalente a Python. Python realmente no es una herramienta de línea única de shell, pero a veces se puede engatusar para que coopere. Lo siguiente se puede escribir como una línea (a diferencia de los forbucles, que no pueden ser), pero el desplazamiento horizontal lo hace (aún más) ilegible:

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
fuente
@rici: ¡Buena! Y use en y///lugar de tr///salvarnos un personaje más.
Cuonglm
6

Para los datos CSV, usaría un lenguaje con un analizador CSV real. Por ejemplo 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"
Glenn Jackman
fuente
0

Blockquote

Hola, aquí está el código de Python para reemplazar comas con comillas dobles, las comas se reemplazan con un carácter de barra vertical (|)

Este código de Python es para reemplazar comas entre comillas dobles

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

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

si se reemplaza con nulo 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
fuente
Se necesita poca explicación.
Mestizo
Este código de Python se usa para reemplazar cosas entre comillas dobles
Vijay Kumar Akarapu