2008-11-13 2 views
46

Lorsque vous utilisez des expressions régulières dans Ruby, quelle est la différence entre $ 1 et \ 1?

Répondre

78

\ 1 est une référence arrière qui ne fonctionne que dans le même sub ou gsub appel de méthode, par exemple:

"foobar".sub(/foo(.*)/, '\1\1') # => "barbar" 

1 $ est une variable globale qui peut être utilisé dans le code plus tard:

if "foobar" =~ /foo(.*)/ then 
    puts "The matching word was #{$1}" 
end 

Sortie:

"The matching word was bar" 
# => nil 
+0

Notez que [le traitement des guillemets simples et doubles par Ruby] (http://stackoverflow.com/a/3028799/303896) peut vous gêner lorsque vous essayez d'utiliser des références arrières. – alxndr

+0

n'a pas beaucoup compris, quelqu'un peut-il fournir plus d'explications? – YasirAzgar

+0

@YasirAzgar '.sub()' est un appel de méthode. ''\'' ne peut (apparemment) être utilisé que dans le cadre d'un appel de méthode' sub' ou 'gsub'. Dans le premier exemple, '' foobar ".sub (/ foo (. *) /, '\ 1 \ 1')', ''\'' est dans la portée de la méthode' sub'. Dans le second exemple, '$ 1' est référencé en dehors d'une méthode' sub'/'gsub'. L'exemple montre qu'il est référencé peu après un appel '= ~', mais ce n'est pas pertinent. Apparemment, l'utilisation d'une regex définit '$ 1', qui, en tant que variable globale, peut être référencée n'importe où. – John

29

Gardez à l'esprit qu'il existe une troisième option, la b forme de verrouillage de sub. Parfois vous en avez besoin. Supposons que vous souhaitiez remplacer du texte par l'inverse de ce texte. Vous ne pouvez pas utiliser 1 $ parce qu'il est pas lié assez rapidement:

"foobar".sub(/(.*)/, $1.reverse) # WRONG: either uses a PREVIOUS value of $1, 
            # or gives an error if $1 is unbound 

Vous pouvez également ne pas utiliser \1, parce que la méthode sub fait juste un texte simple substitution de \1 avec le texte capturé approprié, il n'y a pas de magie qui se déroule ici:

"foobar".sub(/(.*)/, '\1'.reverse) # WRONG: returns '1\' 

donc, si vous voulez faire quoi que ce soit de fantaisie, vous devez utiliser la forme de sub bloc (1 $, 2 $, $ `, « etc. $ seront disponibles):

"foobar".sub(/.*/){|m| m.reverse} # => returns 'raboof' 
"foobar".sub(/(...)(...)/){$1.reverse + $2.reverse} # => returns 'oofrab' 
+1

Votre exemple pourrait être trompeur - la correspondance est ce qui est passé au bloc, pas les groupes de correspondance. Donc, si vous vouliez changer "foobar" en "foorab", vous auriez à faire 'str.sub (/ (foo) (\ w +) /) {$ 1 + $ 2.reverse}' – rampion

+1

Voir ri Chaîne # sub : Dans la forme de bloc, la chaîne de correspondance actuelle est transmise en tant que paramètre et les variables telles que $ 1, $ 2, $ ', $ & et $ 'seront définies de manière appropriée. La valeur renvoyée par le bloc sera substituée à la correspondance sur chaque appel. – rampion

+0

À droite, je vais modifier pour l'effacer. –