Saturday, February 19, 2011

$1 and \1 in Ruby

When using regular expressions in Ruby, what is the difference between $1 and \1?

From stackoverflow
  • \1 is a backreference which will only work in the same sub or gsub method call, e.g.:

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

    $1 is a global variable which can be used in later code:

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

    (prints "The matching word was bar")

  • Keep in mind there's a third option, the block form of sub. Sometimes you need it. Say you want to replace some text with the reverse of that text. You can't use $1 because it's not bound quickly enough:

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

    You also can't use \1, because the sub method just does a simple text-substitution of \1 with the appropriate captured text, there's no magic taking place here:

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

    So if you want to do anything fancy, you should use the block form of sub ($1, $2, $`, $' etc. will be available):

    "foobar".sub(/.*/){|m| m.reverse} # => returns 'raboof'
    "foobar".sub(/(...)(...)/){$1.reverse + $2.reverse} # => returns 'oofrab'
    
    rampion : Your example could be misleading - the match is what's passed to the block, not the matchgroups. So, if you wanted to change "foobar" to "foorab", you'd have to do `str.sub(/(foo)(\w+)/) { $1 + $2.reverse }`
    rampion : See ri String#sub: In the block form, the current match string is passed in as a parameter, and variables such as $1, $2, $`, $&, and $' will be set appropriately. The value returned by the block will be substituted for the match on each call.
    Brian Carper : Right, I'll edit to clear it up.
    Adrian : You saved my day!
  • That "\1\1" in the main answer should be '\1\1'

0 comments:

Post a Comment