# Confused regarding text example

**URL:** <https://www.ruby-forum.com/t/confused-regarding-text-example/149061>\
**Category:** Ruby\
**Created:** [September 19, 2008, 9:32pm UTC](https://www.ruby-forum.com/t/confused-regarding-text-example/149061 "2008-09-19T21:32:50Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![paradise](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8e7dd6/32.png) [@paradise](https://www.ruby-forum.com/u/paradise)\
**Post date:** [September 19, 2008, 9:32pm UTC](https://www.ruby-forum.com/t/confused-regarding-text-example/149061/1 "2008-09-19T21:32:50Z")

</div>

Hey,

So as I am reviewing Ruby I came across the old find strings with xyz  
pattern.

The code is as follows:

class WordIndex  
def initialize  
@index = {}  
end  
def add\_to\_index(obj, \*phrases)  
phrases.each do |phrase|  
phrase.scan(/\w[\w’]+/) do |word| # extract each word  
word.downcase!  
@index[word] = [] if @index[word].nil?  
@index[word].push(obj)  
end  
end  
end  
def lookup(word)  
@index[word.downcase]  
end  
end

So here is my understanding:

phrases contains the phases/patterns to look for. |phrase| is replaced  
by each of the phrases to check for.

After that, I become a bit ocnfused. I know they are looking for the  
phrase in each of the words (.\w\w’]+/) but how does that work?

How is each string broken down into “words”? w

hy is that done anyway (why not just find the pattern and move on?).

Also, what is obj exactly (other than an object)? How is it being  
formed so it can be pushed into the stack?

Finally, what does index[word] represent? I am guessing a hash…

---

<div class="post-metadata">

**Author:** ![paradise](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8e7dd6/32.png) [@paradise](https://www.ruby-forum.com/u/paradise)\
**Post date:** [September 19, 2008, 10:08pm UTC](https://www.ruby-forum.com/t/confused-regarding-text-example/149061/2 "2008-09-19T22:08:56Z")

</div>

class WordIndex  
def initialize  
@index = {}  
end  
def add\_to\_index(obj, \*phrases)  
phrases.each do |phrase|  
phrase.scan(/\w[\w’]+/) do |word| # extract each word  
word.downcase!  
@index[word] = [] if @index[word].nil?  
@index[word].push(obj)  
end  
end  
end  
def lookup(word)  
@index[word.downcase]  
end  
end

phrases contains the phases/patterns to look for. |phrase| is replaced  
by each of the phrases to check for.

the \*phrases in the method signature says that it takes a variable  
number of  
arguments, you use those as an array of values.

phrases.each do |phrase|

# code

end  
this piece of code defines a block aka closer that takes one argument.  
the  
each method on array will call this block for every item in the array as  
the  
argument to this block

After that, I become a bit ocnfused. I know they are looking for the  
phrase in each of the words (.\w\w’]+/) but how does that work?

/\w[\w’]+/ is a shorthand for writing Regexp.new(“/\w[\w’]+/”)  
the scan method on a string will return an array of all the matches of  
that  
regexp:  
[http://ruby-doc.org/core/classes/String.html#M000827](http://ruby-doc.org/core/classes/String.html#M000827)

How is each string broken down into “words”? w

hy is that done anyway (why not just find the pattern and move on?).

The code appears to be adding obj to a hash based on the downcased  
version  
of each word in each phrase.

Also, what is obj exactly (other than an object)? How is it being  
formed so it can be pushed into the stack?

obj is just passed in, it could be anything, it could be the filename  
that  
these words were pulled from… or whatever you would want to retrieve  
based  
on the words in the phrases associated with it.

Finally, what does index[word] represent? I am guessing a hash…  
See above, you are right!  
@index = {}  
is shorthand for @index = Hash.new  
the same way @foo = [] is shorthand for @foo = Array.new

Hope this helps. If I have made anything unclear please feel free to  
email  
me.

---

<div class="post-metadata">

**Author:** ![paradise](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8e7dd6/32.png) [@paradise](https://www.ruby-forum.com/u/paradise)\
**Post date:** [September 20, 2008, 3:10pm UTC](https://www.ruby-forum.com/t/confused-regarding-text-example/149061/3 "2008-09-20T15:10:41Z")

</div>

Alright, I think I got it.

So basically, WordIndex’s obj could be a file, an array of strings, etc.

Phrases is basically a series of phrases (my mind just went blank on the  
correct terminology).

Scan breaks down the series into an array containing the phrases.

The do |word| end look is activated with each item in the array. The  
string is modified and is turned into all lower case,. Next, a check is  
made tosee if index[word] is empty. If so, then it’s turned into an  
empty Hash.

Finally, the object is pushed into the Hash that had the wanted string.  
Of course, if, say a file, had the same string three times…it would be  
listed three times.

And the thing being “returned” is the @index[word] so to speak, correct?  
That is, the way you can access the Hash.

---

<div class="post-metadata">

**Author:** ![paradise](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8e7dd6/32.png) [@paradise](https://www.ruby-forum.com/u/paradise)\
**Post date:** [September 20, 2008, 12:22am UTC](https://www.ruby-forum.com/t/confused-regarding-text-example/149061/4 "2008-09-20T00:22:32Z")

</div>

On Fri, Sep 19, 2008 at 9:25 PM, Dave L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> end  
> @index[word.downcase]  
> end  
> end
> 
> So here is my understanding:
> 
> phrases contains the phases/patterns to look for. |phrase| is replaced  
> by each of the phrases to check for.

What it seems to me is that the code is a way to classify objects based  
on each  
word of a set of phrases, which is somehow related to that object. For  
example,  
it could be an html page and each phrase is a part of the text present  
on the page,  
a file and its contents, etc.

In the method \*phrases means that phrases will be an array containing  
all parameters  
passed to the method. For example:

irb(main):001:0\> def a(obj, \*phrases)  
irb(main):002:1\> puts phrases.class  
irb(main):003:1\> p phrases  
irb(main):004:1\> end  
=\> nil  
irb(main):005:0\> a(“an obj”, “the first phrase”, “the second one”, “3rd  
one”)  
Array  
[“the first phrase”, “the second one”, “3rd one”]  
=\> nil

Then, the each method will call the block (do … end) passing each of  
the phrases as the block parameter (phrase).

> After that, I become a bit ocnfused. I know they are looking for the  
> phrase in each of the words (.\w\w’]+/) but how does that work?

Scanning will iterate through the phrase searching for the patters,  
and then pass the block  
each result. The result is the section of the string that matches. And  
what sections  
match this pattern? A word letter, followed by any word letter or a '.  
For example:

irb(main):019:0\> re = /\w[\w’]+/  
=\> /\w[\w’]+/  
irb(main):020:0\> “this is a normal sentence”.scan(re) {|x| p x}  
“this”  
“is”  
“normal”  
“sentence”

As you can see, the “a” has been skipped, since the regexp is asking  
for at least two consecutive word letters, or a word letter and a '.

> How is each string broken down into “words”? w

Scanning the sentence with that regexp does the splitting.

> hy is that done anyway (why not just find the pattern and move on?).

Because what the code is doing is retreiving every two letter or more  
word  
to index the object through that word. For each word then, it is  
creating an  
array where it stores the object. This means that at the end you have a  
hash with each word in every sentence as a key, and whose value is an  
array containing all objs related to that word.

> Also, what is obj exactly (other than an object)? How is it being  
> formed so it can be pushed into the stack?

Well, let’s imagine an example of how this method could be used:  
I want to read all txt files in a folder and index the name of the file  
based on each word in the file.

index = WordIndex.new  
Dir[“\*.txt”].each do |file|  
lines = File.open(file) {|f| f.readlines.map {|l| l.chomp}}  
index.add\_to\_index(file, \*lines)  
end

Now we can locate all files that contain a word:

%w{cat dog}.each {|word| puts "Files that contain ‘#{word}’:  
#{index.lookup (word)}

For example I have three files:

one.txt:  
I have a dog  
I have a cat

two.txt:  
I have a dog, and nothing else.  
I do have a car too.

three.txt:  
I love my cat  
I don’t love anything else

$ ruby wordindex.rb

Files that contain ‘cat’: one.txt,three.txt  
Files that contain ‘dog’: one.txt,two.txt

So, you have indexed the contents of the files per word.

> Finally, what does index[word] represent? I am guessing a hash…

@index is a hash. @index[word] is an array.

And btw, you can initialize a hash like this and remove a line:

@index = Hash.new {|h,k| h[k] = []}

and remove this line:

@index[word] = [] if @index[word].nil?

Hope this helps,

Jesus.
