tuo regex ha bisogno di essere un po 'più audace, nel caso in cui le quotazioni si verificano all'inizio del primo valore, o alla fine dell'ultimo valore:
csv = <<ENDCSV
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"
ENDCSV
puts csv.gsub(/(?<!^|,)"(?!,|$)/,'""')
#=> 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"
Quanto sopra regex utilizza lookbehind negativo e asserzioni lookahead negativo (ancore) disponibili in Ruby 1.9.
(?<!^|,)
- immediatamente precedente questo posto non ci deve essere un inizio di riga (^
) o una virgola
"
- trovare una doppia citazione
(?!,|$)
- subito dopo questo posto non ci deve essere o una virgola o alla fine della linea ($
)
Come bonus, dal momento che non hai realmente catturare i caratteri su entrambi i lati, non c'è bisogno di preoccuparsi di un utilizzare \1
correttamente nella stringa di sostituzione.
Per ulteriori informazioni, consultare la sezione "Ancoraggi" nello official Ruby regex documentation.
Tuttavia, per il caso in cui si fai necessità di sostituire le partite in uscita, è possibile utilizzare uno dei seguenti:
"hello".gsub /([aeiou])/, '<\1>' #=> "h<e>ll<o>"
"hello".gsub /([aeiou])/, "<\\1>" #=> "h<e>ll<o>"
"hello".gsub(/([aeiou])/){ |m| "<#{$1}>" } #=> "h<e>ll<o>"
Non è possibile utilizzare String interpolazione nel stringa di sostituzione, come avete fatto:
"hello".gsub /([aeiou])/, "<#{$1}>"
#=> "h<previousmatch>ll<previousmatch>"
... perché l'interpolazione stringa accade una volta, prima di è stato eseguito il gsub
. L'utilizzo del modulo di blocco di gsub
richiama nuovamente il blocco per ogni corrispondenza, a quel punto il numero globale $1
è stato popolato correttamente ed è disponibile per l'uso.
Edit: per Ruby 1.8 (perché sulla terra stai usando questo?) È possibile utilizzare:
puts csv.gsub(/([^,\n\r])"([^,\n\r])/,'\1""\2')
Fresco, ho cercato di capire come fare le affermazioni negative in Ruby e non riuscivo a capirlo. –
Grazie a Phrogz, funziona perfettamente solo con Ruby 1.9, puoi consigliare una risposta per Ruby 1.8? –
@MahmoudKhaled Aggiornato per funzionare con Ruby 1.8. (In futuro, se hai bisogno di una versione così antica di Ruby, includi questo nella tua domanda: Ruby 1.9.1, la prima versione stabile della serie 1.9, è stata rilasciata in tre ** ** anni fa.) – Phrogz