¿Cómo usar ruby ​​gsub Regexp con muchas coincidencias?

Tengo el contenido del archivo csv con comillas dobles dentro del texto citado

test,first,line,"you are a "kind" man",thanks again,second,li,"my "boss" is you",good 

Necesito reemplazar cada comilla doble que no esté precedida o seguida por una coma por “”

 test,first,line,"you are a ""kind"" man",thanks again,second,li,"my ""boss"" is you",good 

por lo que “se sustituye por”

Lo intenté

 x.gsub(/([^,])"([^,])/, "#{$1}\"\"#{$2}") 

pero no funcionó

Su expresión regular debe ser un poco más en negrita, en caso de que las comillas aparezcan al comienzo del primer valor, o al final del último valor:

 csv = < test,first,line,"you are a ""kind"" man",thanks #=> again,second,li,"my ""boss"" is you",good #=> more,"""Someone"" said that you're ""cute""",yay #=> "watch out for this",and,also,"this test case" 

La expresión regular anterior usa aserciones de lookbeth negativo y lookahead negativo (anclas) disponibles en Ruby 1.9.

  • (? : Inmediatamente antes de este punto no debe haber un inicio de línea ( ^ ) ni una coma
  • " - encontrar una cita doble
  • (?!,|$) : Inmediatamente después de este punto no debe haber una coma ni un final de línea ( $ )

Como beneficio adicional, ya que en realidad no capturó los caracteres en ninguno de los lados, no debe preocuparse por usar \1 correctamente en la cadena de reemplazo.

Para obtener más información, consulte la sección "Anclas" en la documentación oficial de expresiones regulares de Ruby .


Sin embargo, en el caso de que necesite reemplazar coincidencias en su salida, puede usar cualquiera de los siguientes:

 "hello".gsub /([aeiou])/, '<\1>' #=> "hll" "hello".gsub /([aeiou])/, "<\\1>" #=> "hll" "hello".gsub(/([aeiou])/){ |m| "<#{$1}>" } #=> "hll" 

No puedes usar la interpolación de cadenas en la cadena de reemplazo, como hiciste:

 "hello".gsub /([aeiou])/, "<#{$1}>" #=> "hll" 

... porque esa interpolación de cadenas ocurre una vez, antes de que se haya ejecutado el gsub . El uso de la forma de bloque de gsub re-invoca el bloque para cada coincidencia, momento en el cual el $1 global se ha completado correctamente y está disponible para su uso.


Edición : Para Ruby 1.8 (¿por qué demonios estás usando eso?) Puedes usar:

 puts csv.gsub(/([^,\n\r])"([^,\n\r])/,'\1""\2') 

Asumiendo que s es una cadena, esto funcionará:

 puts s.gsub(/([^,])"([^,])/, "\\1\"\"\\2")