Cómo replace espacio simple o doble en un file de text cuando entre comillas

Tengo un file CSV con algunos campos cotizados, pero las inputs entre comillas están separadas por espacios dobles o simples. Necesito que estos sean reemplazados por comas.

Línea de ejemplo:

This is okay,"ABC DEF GHI",123,"This is not okay",remove,spaces,within,quotes

Y cómo debería verse:

This is okay,"ABC,DEF,GHI",123,"This,is,not,okay",remove,spaces,within,quotes

 perl -pe 's/".*?"/do{$a = $&; $a =~ s: +:,:g; $a}/ge;' 

Básicamente, esto es solo un reemploop de regex global s/regex/replacement/g . La expresión regular es ".*?" , coincide con cada subcadena que comienza con " y termina con la siguiente " . Las partes difíciles son:

  • El reemploop no es una cadena, sino una expresión que se evalúa. (Ese es el significado del modificador e después de g .)
  • La expresión que se evalúa es nuevamente una sustitución de expresiones regulares global s:regex:replacement:g que reemplaza cualquier secuencia de espacios no vacía por una coma. (No podemos usar el mismo delimitador que en el reemploop externo, entonces usamos : vez de / )
  • Para ejecutar el reemploop interno de expresiones regulares, tenemos que asignar la subcadena coincidente del reemploop $& a alguna otra variable $a , luego realizar el reemploop interno en $a , y finalmente imprimir $a .

Con una versión perl suficientemente reciente, se puede evitar la asignación a una variable auxiliar. Usando el modificador r , el reemploop interno se puede realizar directamente en una copy de la subcadena $& (gracias a Stéphane Chazelas):

 perl -pe 's/".*?"/$&=~s: +:,:gr/ge;' 

Considera esta solución awk de fuerza bruta:

 awk -F, -v OFS=, ' { for(i=1;i<=NF;i++) if ($i ~ /^".*"$/) gsub(" +", ",", $i) print $0 }' 

Le dice a awk que divida los loggings en comas, señalando que esto se romperá si alguno de sus campos contiene una coma. – y usando OFS para indicarle a la statement impresa que recombine los campos con comas. El bucle for recorre cada campo de la línea, y si el campo comienza ^ con una comilla doble, tiene caracteres .* Y termina $ con una comilla doble, a continuación, reemplace globalmente en ese campo $i cualquier cantidad de espacios con comas Después de recorrer los campos, imprima todo el logging ( $0 ).

Con GNU awk :

 gawk -v RS=\" ' NR % 2 == 0{gsub(/ +/, ",")} {ORS = RT; print}' 

Es decir, el separador de loggings se convierte en " carácter y los espacios en blanco solo se reemplazan en loggings pares".

RT es la parte específica de GNU.

Lo mismo con GNU sed :

 tr '\n"' '"\n' | sed -E '2~2s/ +/,/g' | tr '"\n' '\n"' 

Más portably:

 tr '\n"' '"\n' | sed 'n;s/ */,/g' | tr '"\n' '\n"' 

funcionaría con algunos otros sed , aunque podría tener problemas si el último carácter de la input no es un " .