Tengo un archivo de entrada delimitado con comas ( ,
). Hay algunos campos encerrados entre comillas dobles que tienen una coma en ellos. Aquí está la fila de muestra
123,"ABC, DEV 23",345,534.202,NAME
Necesito eliminar todas las comas que aparecen dentro de las comillas dobles y las comillas dobles también. Entonces, la línea anterior debe analizarse como se muestra a continuación
123,ABC DEV 23,345,534.202,NAME
Intenté lo siguiente usando sed
pero sin dar los resultados esperados.
sed -e 's/\(".*\),\(".*\)/\1 \2/g'
¿Algún truco rápido con sed
, awk
o cualquier otra utilidad de Unix por favor?
text-processing
sed
awk
csv
mtk
fuente
fuente
Respuestas:
Si las comillas están equilibradas, querrás eliminar las comas entre las otras comillas, esto puede expresarse
awk
así:Salida:
Explicación
Esto
-F"
hace que awk separe la línea en los signos de comillas dobles, lo que significa que cualquier otro campo será el texto entre comillas. La ejecución del ciclo forgsub
, abreviatura de sustituto global, en cualquier otro campo, reemplazando coma (","
) con nada (""
). El1
al final invoca el código de bloque por defecto:{ print $0 }
.fuente
gsub
explicar y explicar brevemente cómo funciona este revestimiento? Por favor.{ print $0 }
. Agregué eso a la explicación también.prefix,"something,otherthing[newline]something , else[newline]3rdline,and,things",suffix
(es decir: varias líneas y anidado "," en cualquier lugar dentro de una comilla doble de varias líneas: toda la"...."
parte debe volver a unirse y el interior,
debe estar unido reemplazado / eliminado ...): su script no verá pares de comillas dobles en ese caso, y no es realmente fácil de resolver (necesita "volver a unir" las líneas que están en un "abierto" (es decir, números impares) comilla doble ... + tenga mucho cuidado si también hay un escape\"
dentro de la cadena)awk -F'"' -v OFS='"' '{ for (I=1; i<=NF; i+=2) gsub(",", "|", $i) } 1' infile
Hay una buena respuesta, usando sed simplemente una vez con un bucle :
Explicación:
:a;
es una etiqueta para la rama adicionals/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /
podría contener 3 partes cerradas[^"]*,\?\|"[^",]*",\?
coincide con una cadena que no contiene comillas dobles, tal vez seguida de un coma o una cadena encerrada por dos comillas dobles, sin coma y tal vez seguida de un coma.ta
se repetirá:a
si els/
comando anterior hizo algún cambio.fuente
Una solución general que también puede manejar varias comas entre comillas balanceadas necesita una sustitución anidada. Implemento una solución en perl, que procesa cada línea de una entrada dada y solo sustituye comas en cada otro par de comillas:
o en resumen
Puede canalizar el texto que desea procesar al comando o especificar el archivo de texto que se procesará como último argumento de línea de comando.
fuente
[^\\]
va a tener el efecto no deseado de hacer coincidir el último carácter dentro de las comillas y retirarlo (\ carácter no), es decir, no se debe consumir ese carácter. Intenta en su(?<!\\)
lugar.[^"]*
para hacer que el partido no expansivo (es decir, coincide con todo, desde uno"
a la siguiente"
):perl -pe 's/"([^"]+)"/($match = $1) =~ (s:,::g);$match;/ge;'
. No reconoce la extravagante idea de que una cita podría escapar con una barra invertida :-)[^"]*
enfoque o el enfoque explícito no codicioso consume menos tiempo de CPU.Usaría un lenguaje con un analizador CSV adecuado. Por ejemplo:
fuente
Tus segundas citas están fuera de lugar:
Además, el uso de expresiones regulares tiende a coincidir con la parte más larga posible del texto, lo que significa que esto no funcionará si tiene más de un campo entre comillas en la cadena.
Una forma que maneja múltiples campos cotizados en sed
Esta es también una forma de resolver esto, sin embargo, con una entrada que puede contener más de una coma por campo citado, la primera expresión en el sed tendría que repetirse tantas veces como el contenido máximo de coma en un solo campo, o hasta que no cambia la salida en absoluto.
La ejecución de sed con más de una expresión debería ser más eficiente que la ejecución de varios procesos sed y un "tr" que se ejecuta con tuberías abiertas.
Sin embargo, esto puede tener consecuencias no deseadas si la entrada no está formateada correctamente. es decir, comillas anidadas, comillas sin terminar.
Usando el ejemplo en ejecución:
Salida:
fuente
sed -r ':r; s/("[^",]+),([^",]*)/\1 \2/g; tr; s/"//g'
.En perl, puede usar
Text::CSV
para analizar esto y hacerlo trivialmente:Puede imprimir con
Text::CSV
pero tiende a conservar las comillas si lo hace. (Aunque, sugeriría que, en lugar de eliminar las comillas para su salida, podría analizar usandoText::CSV
en primer lugar).fuente
Creé una función para recorrer todos los caracteres de la cadena.
Si el carácter es una cita, entonces el cheque (b_in_qt) se marca como verdadero.
Si bien b_in_qt es verdadero, todas las comas se reemplazan con un espacio.
b_in_qt se establece en falso cuando se encuentra la siguiente coma.
fuente