Mr Mikkél
Mr Mikkél

Reputation: 2643

Ruby Regex: negative lookahead with unlimited matching before

I'm trying to be able to match a phrase like:

I request a single car
// or
I request a single person
// or
I request a single coconut tree

but not

I request a single car by id
// nor
I request a single person by id with friends
// nor
I request a single coconut tree by id with coconuts

Something like this works:

/^I request a single person(?!\s+by id.*)/

for strings like this:

I request a single person
I request a single person with friends

But when I replace the person with a matcher (.*) or add the $ to the end, it stops working:

/^I request a single (.*)(?!\s+by id.*)$/

How can I accomplish this but still match in the first match everything before the negative lookahead?

Upvotes: 1

Views: 391

Answers (2)

Mr Mikkél
Mr Mikkél

Reputation: 2643

OK, I think I just got it. Right after asking the question. Instead of a creating lookahead after the thing I want to capture, I create a lookahead before the thing I want to capture, like so:

/^I request a single (?!.*by id.*)(.*[^\s])?\s*$/

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110675

There's no ) to match ( in (.*\). Perhaps that's a typo, since you tested. After fixing that, however, there's still a problem:

"I request a single car by idea" =~ /^I request a single (?!.*by id.*)(.*)$/
  #=> nil

Presumably, that should be a match. If you only want to know if there's a match, you can use:

r = /^I request a single (?!.+?by id\b)/

Then:

"I request a single car by idea" =~ r               #=> 0 
"I request a single person by id with friends" =~ r #=> nil

\b matches a word break, which includes the case where the previous character is the last one in the string. Notice that if you are just checking for a match, there's no need to include anything beyond the negative lookahead.

If you want to return whatever follows "single " when there's a match, use:

r = /^I request a single (?!.+?by id\b)(.*)/

"I request a single coconut tree"[r,1]              #=> "coconut tree"
"I request a single person by id with friends"[r,1] #=> nil

Upvotes: 1

Related Questions