# Hash

**URL:** <https://www.ruby-forum.com/t/hash/122089>\
**Category:** Ruby\
**Created:** [December 4, 2007, 3:30pm UTC](https://www.ruby-forum.com/t/hash/122089 "2007-12-04T15:30:47Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![johnsmith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@johnsmith](https://www.ruby-forum.com/u/johnsmith)\
**Post date:** [December 4, 2007, 3:30pm UTC](https://www.ruby-forum.com/t/hash/122089/1 "2007-12-04T15:30:47Z")

</div>

Hi

iv started writing a class which reads the data from a text file and  
counts the number of Tags

however im having a struggle as I want to split the tag and the data  
into a hash i.e the Tag is the index and the data is the rest

if anyone could provide me with any psuedo code i’d be very appreciative  
my code is below

Many Thanks

text file:

Tag: ref1  
Type: Book  
Author: Little, S R

Tag: ref2  
Type: Journal  
Author: Smith, J

Tag: ref3  
Type: Conference Paper  
Author: Williams, M

Tag: ref4  
Type: Book  
Author: Jones, M B

ruby class:

#!/usr/local/bin/ruby

# 

# 

# 

require ‘getoptlong’

opts = GetoptLong.new(  
[’–style’, ‘-n’, GetoptLong::NO\_ARGUMENT],  
[’–database’, ‘-i’, GetoptLong::REQUIRED\_ARGUMENT]  
)

$linecount = 0

opts.each do |opt, arg|  
case opt  
when ‘–style’  
require arg  
when ‘–database’  
end  
end

# 

# 

# 

# process options

# 

# 

# 

File.open(‘reference.txt’).each do |line|  
if line =~ /^tag:/i  
$linecount += 1  
end  
end  
puts $linecount

#

---

<div class="post-metadata">

**Author:** ![johnsmith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@johnsmith](https://www.ruby-forum.com/u/johnsmith)\
**Post date:** [December 4, 2007, 4:14pm UTC](https://www.ruby-forum.com/t/hash/122089/2 "2007-12-04T16:14:44Z")

</div>

Johnathan S. wrote:

> File.open(‘reference.txt’).each do |line|  
> if line =~ /^tag:/i  
> $linecount += 1  
> end  
> end  
> puts $linecount
> 
> #

try something like this:

linecount = 0  
results = []  
hash = {}  
File.open(‘reference.txt’).each do |line|  
m = line.match /^(\w+):\s\*([\w+,\s]+)$/  
unless m  
results \<\< hash unless hash.empty?  
hash = {}  
else  
linecount += 1  
hash[m[1]] = m[2].chomp  
end  
end

---

<div class="post-metadata">

**Author:** ![johnsmith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@johnsmith](https://www.ruby-forum.com/u/johnsmith)\
**Post date:** [December 4, 2007, 4:33pm UTC](https://www.ruby-forum.com/t/hash/122089/3 "2007-12-04T16:33:37Z")

</div>

On Dec 4, 7:30 am, Johnathan S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Tag: ref3  
> Type: Conference Paper  
> Author: Williams, M
> 
> Tag: ref4  
> Type: Book  
> Author: Jones, M B

info = {}  
last\_tag = nil

# Could be File.readlines

DATA.each\_line{ |line|  
\_, key, data = line.match( /^(\w+): (.+)/ ).to\_a  
next unless key # skip blank lines  
if key == “Tag”  
last\_tag = data  
info[data] = {}  
else  
info[last\_tag][key] = data  
end  
}

require ‘pp’  
pp info  
#=\> {"ref4 "=\>{“Author”=\>“Jones, M B”, “Type”=\>"Book "},  
#=\> "ref3 "=\>{“Author”=\>"Williams, M ", “Type”=\>"Conference Paper "},  
#=\> "ref2 "=\>{“Author”=\>"Smith, J ", “Type”=\>"Journal "},  
#=\> "ref1 "=\>{“Author”=\>"Little, S R ", “Type”=\>"Book "}}

**END**  
Tag: ref1  
Type: Book  
Author: Little, S R

Tag: ref2  
Type: Journal  
Author: Smith, J

Tag: ref3  
Type: Conference Paper  
Author: Williams, M

Tag: ref4  
Type: Book  
Author: Jones, M B

---

<div class="post-metadata">

**Author:** ![johnsmith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@johnsmith](https://www.ruby-forum.com/u/johnsmith)\
**Post date:** [December 4, 2007, 4:51pm UTC](https://www.ruby-forum.com/t/hash/122089/4 "2007-12-04T16:51:47Z")

</div>

On Dec 4, 8:19 am, Phrogz [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> On Dec 4, 7:30 am, Johnathan S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > iv started writing a class which reads the data from a text file and  
> > counts the number of Tags
> 
> > however im having a struggle as I want to split the tag and the data  
> > into a hash i.e the Tag is the index and the data is the rest

Here’s another variation:

# Could be IO.read

info = Hash[ \*DATA.read.split( /\n\n+/ ).map{ |chunk|  
pieces = chunk.scan /^(\w+): (.+)/  
first = pieces.shift  
raise “Uhm…I was assuming Tag comes first” unless first[0] ==  
“Tag”  
[first[1], Hash[\*pieces.flatten] ]  
}.flatten ]

require ‘pp’  
pp info  
#=\> {"ref4 "=\>{“Author”=\>“Jones, M B”, “Type”=\>"Book "},  
#=\> "ref3 "=\>{“Author”=\>"Williams, M ", “Type”=\>"Conference Paper "},  
#=\> "ref2 "=\>{“Author”=\>"Smith, J ", “Type”=\>"Journal "},  
#=\> "ref1 "=\>{“Author”=\>"Little, S R ", “Type”=\>"Book "}}

**END**  
Tag: ref1  
Type: Book  
Author: Little, S R

Tag: ref2  
Type: Journal  
Author: Smith, J

Tag: ref3  
Type: Conference Paper  
Author: Williams, M

Tag: ref4  
Type: Book  
Author: Jones, M B

---

<div class="post-metadata">

**Author:** ![johnsmith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@johnsmith](https://www.ruby-forum.com/u/johnsmith)\
**Post date:** [December 4, 2007, 5:52pm UTC](https://www.ruby-forum.com/t/hash/122089/5 "2007-12-04T17:52:20Z")

</div>

On Dec 4, 9:42 am, Johnathan S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> what i want to do is to create an empty hash every time it encounters a  
> Tag  
> line, and if it encounters any other field, put the field and the  
> related  
> value in the hash, using the field name (e.g Type and Author) as the key
> 
> im not sure if any of the help you provived achieves this but any help  
> on this matter would be greatly appreciated

Unless I’m misunderstanding you, both of the solutions I provided do  
what you are describing.

You can even see this logic explicitly here, in the first solution:  
if key == “Tag”  
last\_tag = data  
info[data] = {}  
else  
info[last\_tag][key] = data  
end

Does the output not look like what you expect?

pp info  
#=\> {"ref4 "=\>{“Author”=\>“Jones, M B”, “Type”=\>"Book "},  
#=\> "ref3 "=\>{“Author”=\>"Williams, M ", “Type”=\>"Conference Paper  
"},  
#=\> "ref2 "=\>{“Author”=\>"Smith, J ", “Type”=\>"Journal "},  
#=\> "ref1 "=\>{“Author”=\>"Little, S R ", “Type”=\>"Book "}}

If not, what actual output did you want?

---

<div class="post-metadata">

**Author:** ![johnsmith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@johnsmith](https://www.ruby-forum.com/u/johnsmith)\
**Post date:** [December 4, 2007, 5:41pm UTC](https://www.ruby-forum.com/t/hash/122089/6 "2007-12-04T17:41:56Z")

</div>

Hi,

thanks for the awesome response I appreciate it

however, i think i may have misunderstood what i was trying to achieve.

what i want to do is to create an empty hash every time it encounters a  
Tag  
line, and if it encounters any other field, put the field and the  
related  
value in the hash, using the field name (e.g Type and Author) as the key

im not sure if any of the help you provived achieves this but any help  
on this matter would be greatly appreciated

many thanks

---

<div class="post-metadata">

**Author:** ![johnsmith](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@johnsmith](https://www.ruby-forum.com/u/johnsmith)\
**Post date:** [December 4, 2007, 6:20pm UTC](https://www.ruby-forum.com/t/hash/122089/7 "2007-12-04T18:20:22Z")

</div>

im just expecting an output of every time it encounters a tag to create  
an empty hash containing the other fields using the fields as the key

im having trouble getting the code u provided to work can you see my  
errors?

# 

# 

require ‘getoptlong’

opts = GetoptLong.new(  
[’–style’, ‘-n’, GetoptLong::NO\_ARGUMENT],  
[’–database’, ‘-i’, GetoptLong::REQUIRED\_ARGUMENT]  
)

$linecount = 0

opts.each do |opt, arg|  
case opt  
when ‘–style’  
require arg  
when ‘–database’  
end  
end

# 

# 

# 

# process options

# 

# 

# 

File.open(‘reference.txt’).each do |line|  
if line =~ /^tag:/i  
$linecount += 1  
end  
end  
puts $linecount

info = {}  
last\_tag = nil

data.each\_line{ |line| \_, key, data = line.match( /^(\w+): (.+)/  
).to\_a  
next unless key # skip blank lines  
if key == “Tag”  
last\_tag = data  
info[data] = {}  
else  
info[last\_tag][key] = data  
end  
}

# 

#
