# Newbie regexp question

**URL:** <https://www.ruby-forum.com/t/newbie-regexp-question/68744>\
**Category:** Ruby\
**Created:** [September 15, 2006, 1:37am UTC](https://www.ruby-forum.com/t/newbie-regexp-question/68744 "2006-09-15T01:37:07Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![james-calivar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/2bfe46/32.png) [@james-calivar](https://www.ruby-forum.com/u/james-calivar)\
**Post date:** [September 15, 2006, 1:37am UTC](https://www.ruby-forum.com/t/newbie-regexp-question/68744/1 "2006-09-15T01:37:07Z")

</div>

Hello,

I’m trying to split a formatted text file into four separate columns.  
The data is comprised of lines of text that are bundled into four  
distinct columns, corresponding to a “Required versus Optional”  
variable, a requirement number, a requirement classification (R1=Rev 1,  
F=Future, I=Internal), and a textual description of the requirement.

My raw data looks like this in the input text file:

R [01] R1 The system shall support “emergency call processing”  
R [02] R1 The system shall support “local call processing”  
R [08] F The system shall provide a command-line user interface  
R [723] F The system shall provide 6 10/100/1000 Ethernet interfaces  
R [11] F The system shall support VoIP networks  
R [398] R1 The system shall contain 2 control boards  
O [327] I The system should support hotswapping of all internal boards  
R [19] I The system shall be able to detect transmission errors  
R [631] F The system shall continue processing data as long as a call is  
active.

I’ve set up a loop to process each line in the input file, and what I’d  
like to get is four separate variables containing on a line-by-line  
basis the data corresponding to the four distinct columns. The problem  
is my regexp experience is next to nothing, and I can’t figure out how  
to extract the data I want since my fourth column contains whitespace  
(I’d have used that as my column separator otherwise).

Here’s my loop:

File.open(textfile, “r”) do |input\_file|  
while line = input\_file.gets  
output\_file \<\< line  
end  
end

What can I replace the simple copy statement (output\_file \<\< line) with  
in order to get what I want?

Thanks in advance, I hope this question makes some sense.

James

---

<div class="post-metadata">

**Author:** ![james-calivar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/2bfe46/32.png) [@james-calivar](https://www.ruby-forum.com/u/james-calivar)\
**Post date:** [September 15, 2006, 2:10am UTC](https://www.ruby-forum.com/t/newbie-regexp-question/68744/2 "2006-09-15T02:10:51Z")

</div>

James C. wrote:

> R [01] R1 The system shall support “emergency call processing”  
> R [02] R1 The system shall support “local call processing”  
> R [08] F The system shall provide a command-line user interface  
> R [723] F The system shall provide 6 10/100/1000 Ethernet interfaces  
> R [11] F The system shall support VoIP networks  
> R [398] R1 The system shall contain 2 control boards  
> O [327] I The system should support hotswapping of all internal boards  
> R [19] I The system shall be able to detect transmission errors  
> R [631] F The system shall continue processing data as long as a call is  
> active.

try this one

open(“file”).read.scan(/(\w)\s+(.+?)\s+(\w+)\s+(.\*?)\n?$/){|req,num,cls,dsc|  
…}

lopex

---

<div class="post-metadata">

**Author:** ![james-calivar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/2bfe46/32.png) [@james-calivar](https://www.ruby-forum.com/u/james-calivar)\
**Post date:** [September 15, 2006, 2:14am UTC](https://www.ruby-forum.com/t/newbie-regexp-question/68744/3 "2006-09-15T02:14:51Z")

</div>

On Sep 14, 2006, at 6:37 PM, James C. wrote:

> What can I replace the simple copy statement (output\_file \<\< line)  
> with  
> in order to get what I want?

My wife, Dana Gray, is still learning Ruby so I gave her this problem  
as a test. 😉 She suggests the code below.

James Edward G. II

DATA.each do |line|  
line =~ /^(\w)\s+(\S+)\s+(\S+)\s+(.+)/  
p [$1, $2, $3, $4]  
end

**END**  
R [01] R1 The system shall support “emergency call processing”  
R [02] R1 The system shall support “local call processing”  
R [08] F The system shall provide a command-line user interface  
R [723] F The system shall provide 6 10/100/1000 Ethernet interfaces  
R [11] F The system shall support VoIP networks  
R [398] R1 The system shall contain 2 control boards  
O [327] I The system should support hotswapping of all internal boards  
R [19] I The system shall be able to detect transmission errors  
R [631] F The system shall continue processing data as long as a call  
is active.

---

<div class="post-metadata">

**Author:** ![james-calivar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/2bfe46/32.png) [@james-calivar](https://www.ruby-forum.com/u/james-calivar)\
**Post date:** [September 15, 2006, 2:16am UTC](https://www.ruby-forum.com/t/newbie-regexp-question/68744/4 "2006-09-15T02:16:51Z")

</div>

Marcin MielÅ¼yÅ?ski wrote:

Ooops,

the newline in regexp is not needed…

> try this one
> 
> open(“file”).read.scan(/(\w)\s+(.+?)\s+(\w+)\s+(.\*?)$/){|req,num,cls,dsc|  
> …}
> 
> lopex

lopex

---

<div class="post-metadata">

**Author:** ![james-calivar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/2bfe46/32.png) [@james-calivar](https://www.ruby-forum.com/u/james-calivar)\
**Post date:** [September 15, 2006, 2:16am UTC](https://www.ruby-forum.com/t/newbie-regexp-question/68744/5 "2006-09-15T02:16:51Z")

</div>

On 14-Sep-06, at 7:37 PM, James C. wrote:

> active.  
> Here’s my loop:
> 
> Thanks in advance, I hope this question makes some sense.

You have a number of options - if your data is tab delimited (i.e.  
the first “two” coluumns are really one):

s = ‘R [01] R1 The system shall support “emergency call processing”’  
p s.split(/\t/)

=\> [“R [01]”, “R1”, “The system shall support "emergency call  
processing"”]

or you can just split on whitespace and specify a limit on the number  
of fields:

s = ‘R [01] R1 The system shall support “emergency call processing”’  
p s.split(/\s+/, 4)

=\> [“R”, “[01]”, “R1”, “The system shall support "emergency call  
processing"”]

Or you can use a regex (ick 😉

Hope this helps,

Mike

–

Mike S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
[http://www.stok.ca/~mike/](http://www.stok.ca/~mike/)

The “`Stok’ disclaimers” apply.

---

<div class="post-metadata">

**Author:** ![james-calivar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/2bfe46/32.png) [@james-calivar](https://www.ruby-forum.com/u/james-calivar)\
**Post date:** [September 15, 2006, 4:46pm UTC](https://www.ruby-forum.com/t/newbie-regexp-question/68744/6 "2006-09-15T16:46:46Z")

</div>

I suck at regex too, I tried this as an exercise and came up with the  
below. It’s less concise than previous solutions, but it works as far  
as I can tell:

Row = Struct.new(:col1, :col2, :col3, :col4)  
rows = Array.new()  
regex = /([A-Z])\s([[0-9]+])\s([A-Z1-9]+)\s(.+)/

File.open(“file.txt”) do |file|  
while (line = file.gets)  
m = line.match(regex)  
rows \<\< Row.new(m[1], m[2], m[3], m[4])  
end  
end

puts rows.flatten

#output =\>

#\<struct Row col1=“R”, col2="[01]", col3=“R1”, col4=“The system shall  
support “emergency call processing””\>  
#\<struct Row col1=“R”, col2="[02]", col3=“R1”, col4=“The system shall  
support “local call processing””\>  
#\<struct Row col1=“R”, col2="[08]", col3=“F”, col4=“The system shall  
provide a command-line user interface”\>  
#\<struct Row col1=“R”, col2="[723]", col3=“F”, col4=“The system shall  
provide 6 10/100/1000 Ethernet interfaces”\>  
#\<struct Row col1=“R”, col2="[11]", col3=“F”, col4=“The system shall  
support VoIP networks”\>  
#\<struct Row col1=“R”, col2="[398]", col3=“R1”, col4=“The system shall  
contain 2 control boards”\>  
#\<struct Row col1=“O”, col2="[327]", col3=“I”, col4=“The system should  
support hotswapping of all internal boards”\>  
#\<struct Row col1=“R”, col2="[19]", col3=“I”, col4=“The system shall be  
able to detect transmission errors”\>  
#\<struct Row col1=“R”, col2="[631]", col3=“F”, col4=“The system shall  
continue processing data as long as a call is active.”\>

-Steven
