How to Create a Dynamic Regular Expression in Ruby

Is it possible to create a dynamic regular expression in Ruby

You can use #{} just like in a string.

1.9.2p290 :001 > some_string = "033112"
=> "033112"
1.9.2p290 :002 > a_regex = /[A-Z]{1,4}#{some_string}[A-Z]{1-5}-EQB.html/
=> /[A-Z]{1,4}033112[A-Z]{1-5}-EQB.html/

Ruby how to construct dynamic regexp?

You can use interpolation in the same way as with strings:

/(<\s*?div\s*?id="#{my_id}"\s*?>.*?<\/div>)/im

Regular expression in Ruby dynamic creation

You want to use Regexp.union:

union(pat1, pat2, ...) → new_regexp
union(pats_ary) → new_regexp

Return a Regexp object that is the union of the given patterns, i.e., will match any of its parts. The patterns can be Regexp objects, in which case their options will be preserved, or Strings.

So just this:

regex = Regexp.union(phrases)

For example:

>> phrases = %w[pancakes egg$]
=> ["pancakes", "egg$"]
>> puts Regexp.new(phrases.join('|')).inspect
/pancakes|egg$/
>> puts Regexp.union(phrases).inspect
/pancakes|egg\$/

Note the escaped $ in the union version. There's also Regexp.quote (AKA Regexp.escape) if you need to selectively escape particular strings. Generally you don't want to just mash a bunch of random strings together to build a regex, the regex syntax characters will get you every time; use Regex.union for a big alternation or send your pieces through Regex.escape before putting them together.

You could also do a LIKE query if you wanted to keep it inside the database:

Foo.where('phrase like ?', "%#{params[:some_text]}%")

or skip all the pattern matching stuff and its escaping problems altogether and do a simple string position check:

Foo.where('position(? in phrase) != 0', params[:some_text])

Both of these will do table scans but so will your Foo.all.

ror, how to make a regex dynamic?

In ruby you can create the regexp from a string representation using Regexp.new:

if (params[:to].to_s =~ Regexp.new("^r\\+.*@#{Regexp.quote(SITE_CONFIG['mail_host'])}$")) == nil

Variable containing regex as string/generating regex dynamically and trouble with \b

This isn't hard, but it appears you're making it that way:

foo = '\b[ab]'
Regexp.new(foo) # => /\b[ab]/
/#{foo}/ # => /\b[ab]/

or:

foo = "\\b[ab]"
Regexp.new(foo) # => /\b[ab]/
/#{foo}/ # => /\b[ab]/

Ruby is perfectly happy to use a string to create a pattern, you just have to do it right.

Strings are great building blocks for patterns because we can build patterns up from smaller pieces, then finally join the pieces we want into a large pattern. We do that in all sorts of languages too, not just Ruby.

WORD_BOUNDARY = '\b'
WORD_CHARACTERS = '[a-zA-Z]'
WORD_PATTERN = /#{WORD_BOUNDARY}#{WORD_CHARACTERS}+#{WORD_BOUNDARY}/
WORD_PATTERN # => /\b[a-zA-Z]+\b/

/#{WORD_PATTERN}/ # => /(?-mix:\b[a-zA-Z]+\b)/
Regexp.new(WORD_PATTERN) # => /\b[a-zA-Z]+\b/

It's also important to note the difference between "\b" and '\b'. If the string allows interpolation of variables and escaped values, then \b will be treated as a backspace. That's NOT what you want:

"\b" # => "\b"
"\b".ord # => 8

Instead, use a non-interpreted string:

'\b' # => "\\b"

Or double-escape the word-boundary characters.

You can easily dynamically generate a pattern, you just have to follow the rules for string interpolation and understand that escaped characters have to be double-escaped if the string is interpolated.

Need a regular expression to match a dynamically-determined repeat count

That is not possible in regex since it is not a regular language (that's easy to prove with the Pumping Lemma for Regular Languages). I'm not sure how much more powerful ruby regex is than a true Regular Expression, but I doubt it's powerful enough for this. You can set a finite limit on it and state each possibility like:

a1|aa2|aaa3|aaaa4|aaaaa5||aaaaaa6||aaaaaaa7||How to Create a Dynamic Regular Expression in Ruby8||How to Create a Dynamic Regular Expression in Rubya9

Since all finite lanugages are regular, but it would be much easy to use string operations to count the number of times a letter appears and then parse for that integer in the string right after the last of that letter.

Apply regex to a dynamic Rails link

When you call a _path or _url method, all it does is return a string, so you can gsub that result as you need to.

Note that Rails will treat that as going to /leisure/venuename in any link/form/or redirect due to the # being a location on a particular page, not a unique URL.

Edit

Managed to get a stricter regex working. Problem with .* is it gets slashes and such too.

 path.gsub(/\/[a-zA-Z0-9\-\_]*$/) do |match|
"##{match}"
end

ruby include, dynamic letters and symbols

One way to do this is through Regular Expressions ('regex' for short). Two good sources of information is Regular Expression.info and Rubular which is more Ruby centric.

One way to use regex on a string is the String#match method:

names[2].match(/Q\d\dP\d\d/) # /d stands for digit 

This will return the string if there is a match and it will return nil if there isn't.

"Q42P67".match(/Q\d\dP\d\d/) #=> "Q42P67"
"H33P55".match(/Q\d\dP\d\d/) #=> nil

This is helpful in an if condition since a returned string is 'truthy' and nil is 'falsely'.

names[2] = "Q42P67"
if names[2].match(/Q\d\dP\d\d/)
# Will execute code here
end

names[2] = "H33P55"
if names[2].match(/Q\d\dP\d\d/)
# Will not execute code here
end

I hope that helps until you dig further into your study of Regular Expressions.

EDIT:
Note that the Q and P in /Q\d\dP\d\d/ are capital letters. If case is not important, you can append an 'i' for case-insensitivity. /Q\d\dP\d\d/i will capture "Q42P67" and "q42P67"

Ruby regular expression using variable name

The code you think doesn't work, does:

var = "Value"
str = "a test Value"
p str.gsub( /#{var}/, 'foo' ) # => "a test foo"

Things get more interesting if var can contain regular expression meta-characters. If it does and you want those matacharacters to do what they usually do in a regular expression, then the same gsub will work:

var = "Value|a|test"
str = "a test Value"
str.gsub( /#{var}/, 'foo' ) # => "foo foo foo"

However, if your search string contains metacharacters and you do not want them interpreted as metacharacters, then use Regexp.escape like this:

var = "*This*"
str = "*This* is a string"
p str.gsub( /#{Regexp.escape(var)}/, 'foo' )
# => "foo is a string"

Or just give gsub a string instead of a regular expression. In MRI >= 1.8.7, gsub will treat a string replacement argument as a plain string, not a regular expression:

var = "*This*"
str = "*This* is a string"
p str.gsub(var, 'foo' ) # => "foo is a string"

(It used to be that a string replacement argument to gsub was automatically converted to a regular expression. I know it was that way in 1.6. I don't recall which version introduced the change).

As noted in other answers, you can use Regexp.new as an alternative to interpolation:

var = "*This*"
str = "*This* is a string"
p str.gsub(Regexp.new(Regexp.escape(var)), 'foo' )
# => "foo is a string"


Related Topics



Leave a reply



Submit