19

I have a line of text

this is the line

and I want to return true if one of the elements in that array:

['hey', 'format', 'qouting', 'this']

is a part of the string given above.

So for the line above it should return true.

For this line hello my name is martin it should not.

I know include? but I don't know how to use it here if it helps at all.

4 Answers 4

24
>> s = "this is the line"
=> "this is the line"
>> ['hey', 'format', 'qouting', 'this'].any? { |w| s =~ /#{w}/ }
=> true
>> ['hey', 'format', 'qouting', 'that'].any? { |w| s =~ /#{w}/ }
=> false
>> s2 = 'hello my name is martin'
=> "hello my name is martin"
>> ['hey', 'format', 'qouting', 'this'].any? { |w| s2 =~ /#{w}/ }
=> false
Sign up to request clarification or add additional context in comments.

9 Comments

Well, that was fast, thanks. Would you mind explaining what happens here s =~ /#{w}/ ?
It's a regular expression match. Since regex in Ruby support string interpolation, I use that to create one out of the strings in the array.
I should add that this also will return true if a word is part of a longer word in the string, so if you don't want that, you'll have to match with word boundaries /\b#[w}\b/.
Why dont you use include? instead of regex. It would be more readeable(dont know about performance)..like this ['hey', 'format', 'qouting', 'this'].any? { |w| s.include? w }
@rubyprince: I find regex very readable, especially simple ones like this. And when someone talks about matching something in a string, I'll almost always go down the regex route, because that's what they are there for.
|
16

The simplest way I know to test for inclusion of one string inside another is:

text = 'this is the line'
words = ['hey', 'format', 'qouting', 'this']

words.any? { |w| text[w] }  #=> true

No need for regex, or anything complicated.

require 'benchmark'

n = 200_000
Benchmark.bm(3) do |x|
  x.report("1:") { n.times { words.any? { |w| text =~ /#{w}/ } } }
  x.report("2:") { n.times { text.split(" ").find { |item| words.include? item } } }
  x.report("3:") { n.times { text.split(' ') & words } }
  x.report("4:") { n.times { words.any? { |w| text[w] } } }
  x.report("5:") { n.times { words.any? { |w| text.include?(w) } } }
end

>>          user     system      total        real
>> 1:   4.170000   0.160000   4.330000 (  4.495925)
>> 2:   0.500000   0.010000   0.510000 (  0.567667)
>> 3:   0.780000   0.030000   0.810000 (  0.869931)
>> 4:   0.480000   0.020000   0.500000 (  0.534697)
>> 5:   0.390000   0.010000   0.400000 (  0.476251)

4 Comments

I don't find include? to be more readable than text[w]. It is a bit faster though.
text.include? w suggests that it returns a boolean value whether w is included in text. text[w] at first glance may be interpreted as giving the starting value of w in text.
This will also return true if a word in words is part of the string text. Unlike the regex solution, there is no way to make it only match whole words - that I can see anyway :)
A regex pattern is the only way to test for complete word matches, however that solution can cause the test to run extremely slow unless the pattern being used is written correctly. If patterns are anchored to the string start or end, then the engine can do an extremely fast search. If anchoring isn't possible, then the engine slows down significantly and a simple sub-string match will beat it. And, the more complex the pattern is, the slower it will run; Trying to use look-ahead/behind makes it worse. The smart programmer will test with benchmarks to figure out what is the fastest route.
6

You could split the strling into an array, and check for the intersection between your array and the newly split array, like so.

This is handy because it'll give you more than a true false, it will give you the matched strings.

> "this is the line".split(' ') & ["hey", "format", "quoting", "this"]
=> ["this"] 

If you needed a true / false you could easily do:

> s = "this is the line"
=> "this is the line" 
> intersection = s.split(' ') & ["hey", "format", "quoting", "this"]
=> ["this"] 
> intersection.empty?
=> false

1 Comment

I love this approach for single word checking (e.g. 'hey'). Things fall apart if you need phrase checking, though (e.g. 'hey you').
1
> arr = ['hey', 'format', 'qouting', 'this']
=> ["hey", "format", "qouting", "this"]
> str = "this is the line"
=> "this is the line"
> str.split(" ").find {|item| arr.include? item }
=> "this"
> str.split(" ").any? {|item| arr.include? item }
=> true

2 Comments

you can go the other way also arr.any? { |item| str.include? item }
yep, thats neat.. :). i just started ruby... still doing ruby in c# way :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.