J'ai le contenu d'un fichier csv avec des guillemets dans le texte cité
test,first,line,"you are a "kind" man",thanks
again,second,li,"my "boss" is you",good
Je dois remplacer chaque guillemet double non précédé ou remplacé par une virgule par ""
test,first,line,"you are a ""kind"" man",thanks
again,second,li,"my ""boss"" is you",good
donc "est remplacé par" "
J'ai essayé
x.gsub(/([^,])"([^,])/, "#{$1}\"\"#{$2}")
mais n'a pas fonctionné
Votre expression régulière doit être un peu plus en gras, au cas où les guillemets se produisent au début de la première valeur ou à la fin de la dernière valeur:
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"
Le regex ci-dessus utilise des assertions de lookbehind négatif et d'anticipation négatif (ancres) disponibles dans Ruby 1.9.
(?<!^|,)
- précédant immédiatement ce point, il ne doit pas y avoir non plus de début de ligne (^
) ou une virgule"
- trouver un double guillemet(?!,|$)
- immédiatement après ce point, il ne doit y avoir ni virgule ni fin de ligne ($
)En prime, puisque vous n'avez pas réellement capturé les personnages des deux côtés, vous n'avez pas à vous soucier de l'utilisation de \1
correctement dans votre chaîne de remplacement.
Pour plus d'informations, consultez la section "Ancres" dans le documentation officielle Ruby regex .
Cependant, dans le cas où vous faites devez remplacer les correspondances dans votre sortie, vous pouvez utiliser l'une des options suivantes:
"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>"
Vous ne pouvez pas utiliser l'interpolation de chaîne dans la chaîne de remplacement, comme vous l'avez fait:
"hello".gsub /([aeiou])/, "<#{$1}>"
#=> "h<previousmatch>ll<previousmatch>"
… Parce que cette interpolation de chaîne se produit une fois, avant le gsub
a été exécuté. En utilisant la forme de bloc de gsub
ré-invoque le bloc pour chaque correspondance, à quel point le global $1
a été correctement renseigné et peut être utilisé.
Edit : Pour Ruby 1.8 (pourquoi diable utilisez-vous cela?), Vous pouvez utiliser:
puts csv.gsub(/([^,\n\r])"([^,\n\r])/,'\1""\2')
En supposant que s
est une chaîne, cela fonctionnera:
puts s.gsub(/([^,])"([^,])/, "\\1\"\"\\2")