How to Interpolate a Variable in a Ruby Regex

Interpolating a string into a regex

Same as string insertion.

if goo =~ /#{Regexp.quote(foo)}/
#...

Ruby Regexp Interpolation / Character Class / Global Variable Syntax Clash?

The problem is not $, but #, as #... is usually used for variable expansion in double quoted strings. Like "#{x}".

But the thing is you can also expand global variables directly using #$global, and that explains your problem:

$global = "hello"
"#$global"
=> "hello"

So the solution is to escape either # or $, as this will break the string interpolation state machine out of it's effort to interpret the construct as an interpolation:

puts "\#$global"
=> #$global
puts "#\$global"
=> #$global

EDIT

And just to make it really clear :) The problem is not the Regexp, but you are trying to expand a global variable named $] when you type "#$]":

puts "#$]"
SyntaxError: (irb):22: syntax error, unexpected $undefined

To fix it you need to escape something:

puts "\#$]"
=> #$]

Ruby string interpolate variables but dont alter regex

Heredocs act like double quoted strings as far as backslash-escapes are concerned so you have to manually escape your backslashes by doubling them:

statement = 
<<-HEREDOC
SELECT
field1,
field2
CASE WHEN REGEXP_CONTAINS(field3, r"^\\".*\\"$") THEN 'this'
WHEN REGEXP_CONTAINS(field3, r"^\\[.*]$") THEN 'that'
WHEN field3 = '(not provided)' THEN NULL
ELSE 'the_other' END AS better_field_3,
field4
FROM `#{@dynamic_table_name1}` AS tbl
LEFT JOIN `#{@dynamic_table_name2}` AS tbl2
ON blah = blah
HEREDOC

You could do away with the statement variable and call squish (or squish!) directly on the heredoc as well:

def string_query
<<-HEREDOC.squish
SELECT
field1,
field2
CASE WHEN REGEXP_CONTAINS(field3, r"^\\".*\\"$") THEN 'this'
WHEN REGEXP_CONTAINS(field3, r"^\\[.*]$") THEN 'that'
WHEN field3 = '(not provided)' THEN NULL
ELSE 'the_other' END AS better_field_3,
field4
FROM `#{@dynamic_table_name1}` AS tbl
LEFT JOIN `#{@dynamic_table_name2}` AS tbl2
ON blah = blah
HEREDOC
end

BTW, I'm assuming that @dynamic_table_name1 and @dynamic_table_name2 are known to be safe so that you don't have to worry about interpolating those into your string without escaping.


The double quotes in this:

r"^\".*\"$"

have nothing to do with how Ruby treats the ^\".*\"$. Double quotes inside a heredoc are just meaningless characters, they're nothing special. The heredoc itself provides the "double quoted string" context that is causing your backslashes to be treated specially.

Inserting a Variable into a String using Regex - Ruby

Use double quote. Single-quoted string does not interpolate.

string = "7  -"
variable = "15"
string = string.gsub(/(\S?\d+)(\s)(\s)(\D)/, "\\1\\2#{variable}\\3\\4")
string # => "7 15 -"

Create Regex from String stored in variable with escaped characters (Ruby)

The problem is, that you end up with completely different strings, depending on whether you use single or double quotes:

"\d".chars.to_a
#=> ["d"]

'\d'.chars.to_a
#=> ["\\", "d"]

so when you are using double quotes, the single \ is immediately lost and cannot be recovered by definition, for example:

"\d" == "d"
#=> true

so you can never know what the string contained before the escaping took place. As @FrankSchmitt suggested, use the double backslash or stick with single quotes. There's no other way.

There's an option, though. You can define your regex parts as regexes themselves, instead of strings. They behave exactly as expected:

regex1 = /\d/
#=> /\d/

regex2 = /foobar/
#=> /foobar/

Then, you can build your final regex with #{}-style interpolation, instead of building the regex source from strings:

regex3 = /#{regex1} #{regex2}/
#=> /(?-mix:\d) (?-mix:foobar)/

Reflecting your example this would translate to:

email_regex = /[a-z]*\.com/
whole_regex = /to: #{email_regex}/
#=> /to: (?-mix:[a-z]*\.com)/

You may also find Regexp#escape interesting. (see the docs)

If you run into further escaping problems (with the slashes), you can also use the alternative Regexp literal syntax with %r{<your regex here>}, in which you do not need to escape the / character. For example:

%r{/}
#=> /\//

There's no getting around escaping the backslash \ with \\, though.

Stumped by a simple regex

This is actually a special case of string interpolation with global and instance variables that most seem not to know about. Since string interpolation also occurs within regex in Ruby, I'll illustrate below with strings (since they provide for an easier example):

@foo = "instancefoo"
$foo = "globalfoo"
"#@foo" # => "instancefoo"
"#$foo" # => "globalfoo"

Thus you need to escape the # to prevent it from being interpolated:

/[~!@\#$%^&*()]+/

The only way that I know of to create a non-interpolated regex in Ruby is from a string (note single quotes):

Regexp.new('[~!@#$%^&*()]+')


Related Topics



Leave a reply



Submit