Daniel Viglione
Daniel Viglione

Reputation: 9507

Match multiple words anywhere in string

I want to check if all words in a string selection are present in another string. There will be an arbitrary number of words. This is not an OR. All words MUST be present in the matcher. Order does not matter. For example, when selection is "John Zeni", it must match " John Paul Zeni" because both "John" and "Zeni" are in the matcher. If selection was just "John", then it should match, but since there are multiple words, all words must match. Regex solution is required.

This is what I tried:

selection = "John Zeni"
pattern = selection.split(" ").join("|")
# => "John|Zeni"
/#{Regexp.quote(pattern)}/
# => /John\|Zeni/ 
" John Paul Zeni".match(/#{Regexp.quote(pattern)}/)
# => nil 

Why doesn't it match? The problem is with Regexp.quote I think. It is important that both words match in the matcher. This also should not match:

" John Paul Zeni" =~ /(John|Zach)/ 
# => 1

Upvotes: 0

Views: 515

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110755

("John Zeni".split - "John Paul Zeni".split).empty?
  #=> true

If str may contain punctuation we should remove those characters before splitting.

("John Zeni Lola".split - "John Lola Paul, Zeni.".gsub(/[[:punct:]]/,'').split).empty?
  #=> true

Upvotes: 4

revo
revo

Reputation: 48751

Use positive lookaheads to simulate AND:

string = "Paul Zach"
re = '^(?=.*' + string.split(/\s+/).map{ |x| Regexp.quote(x) }.join(')(?=.*') + ')'
"John Paul Mak Zach Jack Zen" =~ /#{re}/

If matching through multiple lines is a need, enable m flag or use [\s\S] instead of .. You can ensure that words are not within other words using \b token around them.

Note: Order doesn't matter.

Upvotes: 1

Related Questions