regex negative look-ahead in ruby 1.9.3 vs 2.0.0

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



regex negative look-ahead in ruby 1.9.3 vs 2.0.0



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


"bar"


"foo"



Looking at the docs for 1.9.3 and 2.0.0, they seem to support negative look-ahead 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(/(?!^foos).*.bar$/)
# => ["b.bar"] (ruby 2.0.0)
# => ["foo a.bar", "b.bar"] (ruby 1.9.3)



The ruby version on this infrastructure will be upgraded in 4 months, but changing the version sooner isn't an option. How can I make this work in 1.9.3 and preferably continue to work in 2.0?





I think this is Ruby 2.0's bug rather than Ruby 1.9.3's.
– sawa
Apr 11 '14 at 6:34





I just reported this bug to Ruby Core.
– sawa
Apr 11 '14 at 6:41




3 Answers
3



Better use this, which looks more convincing:


matched = array.grep(/^(?!foos).*.bar$/)



NOT starting with foo


NOT



this will work in both 2.1.1 and 1.9.3



only if you want to see what I did:


# ruby-1.9.3-p362
array = ["foo a.bar", "b.bar"]
# => ["foo a.bar", "b.bar"]
matched = array.grep(/(?!^foos).*.bar$/)
# => ["foo a.bar", "b.bar"]
matched = array.grep(/^(?!foos).*.bar$/)
# => ["b.bar"]
matched = array.grep(/(?!^foos).*.bar$/)
# => ["foo a.bar", "b.bar"]

# ruby-2.1.1
array = ["foo a.bar", "b.bar"]
# => ["foo a.bar", "b.bar"]
matched = array.grep(/(?!^foos).*.bar$/)
# => ["b.bar"]
matched = array.grep(/^(?!foos).*.bar$/)
# => ["b.bar"]



Simple solution would be not to use negative look-ahead, if it seems problematic in ruby version you are bound to on production servers. If your example is particular enough you could use select and convenient String methods:


select


array.select str





I would also expect this to be faster (especially if you optimise to have lowest-frequency match first). Although OP may have simplified the question and in reality have pattern-matches instead of "foo" and "bar".
– Neil Slater
Apr 11 '14 at 6:16




It's your regex that's faulty, not Ruby. Ruby 2 seems to be a little more forgiving, is all.



The start anchor (^) should be before the lookahead, not in it. When it fails to match foo at the beginning of the line, the regex engine bumps forward one position and tries again. It's not at the start of the string any more, so ^ doesn't match, the negative lookahead reports success, and the regex matches oo a.bar. (This is a very common mistake.)


^


foo


^


oo a.bar





I think you are right, and that Ruby 2.0 is wrong rather than Ruby 1.9.3.
– sawa
Apr 11 '14 at 6:27





Genius explanation on why this fails too!
– SidOfc
Mar 2 '16 at 14:03






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard