How to match and count

R

Ruby Newbee

Hello,

I have been using awk for some text handling.
Now I'm beginning Ruby (really newbie) and want to find a way in ruby
to do this with awk:

awk '{if ($4~/something/) {i+=1}} END {print i}' file.txt

That means if a line's 4th field match "something" then increase the
counter by 1.
How to write the corresponding ruby code?

Thanks in advance.
 
P

Phrogz

awk '{if ($4~/something/) {i+=1}} END {print i}'  file.txt

That means if a line's 4th field match "something" then increase the
counter by 1.
How to write the corresponding ruby code?

What is a 'field'? Whitespace delimited?
 
P

Phrogz

Yes, thanks.

Here are two ways:

# Don't read the whole file into memory, but do it one line at a time
i = 0
file = File.open( "foo.txt" )
file.each_line do |line|
pieces = line.split( /\s+/ )
i += 1 if pieces[ 3 ] =~ /something/
end


# Just read the whole file at once, assuming it's small enough,
# and create an array of the fourth column's
col = File.read("foo.txt").scan(/.+/).map{ |line| line.scan(/\S+/)
[3] }
i = col.count{ |val| val =~ /something/ }
 
R

Ruby Newbee

2009/11/22 Phrogz said:
# Don't read the whole file into memory, but do it one line at a time
i =3D 0
file =3D File.open( "foo.txt" )
file.each_line do |line|
=C2=A0pieces =3D line.split( /\s+/ )
=C2=A0i +=3D 1 if pieces[ 3 ] =3D~ /something/
end


I like that, thank you!
 
R

Robert Klemme

2009/11/22 Phrogz said:
# Don't read the whole file into memory, but do it one line at a time
i = 0
file = File.open( "foo.txt" )
file.each_line do |line|
pieces = line.split( /\s+/ )
i += 1 if pieces[ 3 ] =~ /something/
end
I like that, thank you!

The code above does not close the file handle properly. Also if can be
done shorter:

File.foreach "file.txt" do |line|
...
end

You can even use Ruby like awk which seems to be rarely done - but it's
possible.
awk '{if ($4~/something/) {i+=1}} END {print i}' file.txt

Can be done like

ruby -nae 'BEGIN {$i=0}; $i+=1 if /something/ =~ $F[3]; END {puts $i}'
file.txt
ruby -nae 'BEGIN {$i=0}; /something/ =~ $F[3] and $i+=1; END {puts $i}'
file.txt

For a script, I'd probably do something similar to what Phrogz suggested
but with the difference that I'd use ARGF. That way you fetch file
names from the command line and do not need to change the script if the
file name changes:

i = 0

ARGF.each do |line|
bit = line.split(/\s+/)[3]
i += 1 if /something/ =~ bit
end

puts i

Or, do the matching in one step which seems more efficient

i = 0

ARGF.each do |line|
i += 1 if /^\s*(?:\S+\s+){3}something/ =~ line
end

puts i

There are about 2,843 million other ways to do it in Ruby.

Kind regards

robert
 
R

Ruby Newbee

2009/11/22 Robert Klemme said:
ruby -nae 'BEGIN {$i=0}; $i+=1 if /something/ =~ $F[3]; END {puts $i}'
file.txt
ruby -nae 'BEGIN {$i=0}; /something/ =~ $F[3] and $i+=1; END {puts $i}'
file.txt

oops this is the same way as Perl's.

I may adjust one point:

should be:
$F[3] =~ /something/;

not:
/something/ =~ $F[3];

After that replace "ruby" to "perl" on above commands and that will be
working too.

Thanks~
 
R

Robert Klemme

2009/11/23 Ruby Newbee said:
2009/11/22 Robert Klemme said:
ruby -nae 'BEGIN {$i=3D0}; $i+=3D1 if /something/ =3D~ $F[3]; END {puts = $i}'
file.txt
ruby -nae 'BEGIN {$i=3D0}; /something/ =3D~ $F[3] and $i+=3D1; END {puts= $i}'
file.txt

oops this is the same way as Perl's.

I may adjust one point:

should be:
$F[3] =3D~ /something/;

not:
=A0/something/ =3D~ $F[3];
Why?

After that replace "ruby" to "perl" on above commands and that will be
working too.

Ah, you want a single program to work both for Perl and Ruby. Thanks
for sharing!

I usually prefer to have the regular expression as the first argument
to =3D~ because for me that seems more natural (the regexp is doing the
matching) and IIRC it is a tad faster (but really only a tad).

Kind regards

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top