Regex negative look-ahead in ruby ​​1.9.3 vs 2.0.0

I need to match array elements that end with "bar" but do not start with "foo" and put the result in a new array.

Looking at documents for versions 1.9.3 and 2.0.0, they seem to support a negative look with the same syntax. Negative look-ahead works as I expect in ruby ​​2.0.0, but doesn't seem to work in ruby ​​1.9.3:

 ["foo a.bar", "b.bar"].grep(/(?!^foo\s).*\.bar$/) # => ["b.bar"] (ruby 2.0.0) # => ["foo a.bar", "b.bar"] (ruby 1.9.3) 

The ruby ​​version of this infrastructure will be updated in 4 months, but changing the version earlier is not an option. How can I do this work in 1.9.3 and it is advisable to continue working in version 2.0?

+6
source share
3 answers

it’s better to use this, which looks more convincing:

 matched = array.grep(/^(?!foo\s).*\.bar$/) 

NOT starting with foo

this will work in both 2.1.1 and 1.9.3

only if you want to see what I did:

 rituraj@rituraj :~$ rvm use ruby-1.9.3-p362 Using /home/rituraj/.rvm/gems/ruby-1.9.3-p362 rituraj@rituraj :~$ irb 1.9.3-p362 :001 > array = ["foo a.bar", "b.bar"] => ["foo a.bar", "b.bar"] 1.9.3-p362 :002 > matched = array.grep(/(?!^foo\s).*\.bar$/) => ["foo a.bar", "b.bar"] 1.9.3-p362 :003 > matched = array.grep(/^(?!foo\s).*\.bar$/) => ["b.bar"] 1.9.3-p362 :004 > matched = array.grep(/(?!^foo\s).*\.bar$/) => ["foo a.bar", "b.bar"] 1.9.3-p362 :005 > ^C 1.9.3-p362 :005 > rituraj@rituraj :~$ rvm list rvm rubies => ruby-1.9.3-p362 [ x86_64 ] * ruby-2.1.1 [ x86_64 ] # => - current # =* - current && default # * - default rituraj@rituraj :~$ rvm use ruby-2.1.1 Using /home/rituraj/.rvm/gems/ruby-2.1.1 rituraj@rituraj :~$ irb 2.1.1 :001 > array = ["foo a.bar", "b.bar"] => ["foo a.bar", "b.bar"] 2.1.1 :002 > matched = array.grep(/(?!^foo\s).*\.bar$/) => ["b.bar"] 2.1.1 :003 > matched = array.grep(/^(?!foo\s).*\.bar$/) => ["b.bar"] 
+7
source

A simple solution would be to not use a negative look ahead if it seems problematic in the ruby ​​version that you are tied to production servers on. If your example is concrete enough, you can use select and the convenient String methods:

 array.select {|str| !str.starts_with?('foo') && str.ends_with?('bar') } 
+4
source

This is your regular expression, which is erroneous, not Ruby. Ruby 2 seems a little more forgiving, everything.

The starting anchor ( ^ ) should be before viewing, and not in it. When it does not match foo at the beginning of the line, the regex engine bends one position and retries. This is not at the beginning of the line anymore, so ^ does not match, a negative report shows success, and the regular expression matches oo a.bar . (This is a very common mistake.)

+3
source

All Articles