Thursday, January 20, 2011

Ruby language for beginners

Containers:-

Containers are entities that contain other entities. Ruby has two native container types, arrays and hashes. Arrays are groups of objects ordered by subscript, while hashes are groups of key->value pairs. Besides these two native container types, you can create your own container types.
Arrays
You've already seen how to initialize an array and how to use the each method to quickly iterate each element:
#!/usr/bin/ruby
presidents = ["Ford", "Carter", "Reagan", "Bush1", "Clinton", "Bush2"]
presidents.each { |i| print i, "\n"}

[slitt@mydesk slitt]$ ./array.rb
Ford
Carter
Reagan
Bush1
Clinton
Bush2
[slitt@mydesk slitt]$

Now let's manipulate the array, starting by deleting the last three presidents:
#!/usr/bin/ruby
presidents = ["Ford", "Carter", "Reagan", "Bush1", "Clinton", "Bush2"]
presidents.pop
presidents.pop
presidents.pop
presidents.each { |i| print i, "\n"}

The pop method deletes the final element. If you were to assign the pop method to a variable, it would store that last element and then delete it from the array. In the preceding code, you pop the last three presidents. Here is the result:
[slitt@mydesk slitt]$ ./array.rb
Ford
Carter
Reagan
[slitt@mydesk slitt]$

Now let's prepend the previous three presidents, Kennedy, Johnson and Nixon:
#!/usr/bin/ruby
presidents = ["Ford", "Carter", "Reagan", "Bush1", "Clinton", "Bush2"]
presidents.pop
presidents.pop
presidents.pop
presidents.unshift("Nixon")
presidents.unshift("Johnson")
presidents.unshift("Kennedy")
presidents.each { |i| print i, "\n"}

The result is as expected:
[slitt@mydesk slitt]$ ./array.rb
Kennedy
Johnson
Nixon
Ford
Carter
Reagan
[slitt@mydesk slitt]$

However, you might not like the idea of prepending in the reverse order. In that case, prepend all three at once:
#!/usr/bin/ruby
presidents = ["Ford", "Carter", "Reagan", "Bush1", "Clinton", "Bush2"]
presidents.pop
presidents.pop
presidents.pop
presidents.unshift("Kennedy", "Johnson", "Nixon")
presidents.each { |i| print i, "\n"}

Ruby arrays have methods shift, unshift, push, and pop:
METHOD ACTION ARGUMENT RETURNS
push Appends its argument to the end of the array. Element(s) to be appended to end of the array. A string consisting of the concatination of all non-nil elements in the array AFTER the action was taken.
pop Returns the last element in the array and deletes that element. None. The last element of the array.
shift Returns the first element of the array, deletes that element, and shifts all other elements down one location to fill its empty spot. None. The first element in the array.
unshift Shifts all elements of the array up one, and places its argument at the beginning of the array. Element(s) to be prepended to start of array. A string consisting of the concatination of all non-nil elements in the array AFTER the action was taken.

You can assign individual elements of an array:
#!/usr/bin/ruby
presidents = []
presidents[2] = "Adams"
presidents[4] = "Madison"
presidents[6] = "Adams"
presidents.each {|i| print i, "\n"}
print "=======================\n"
presidents[6] = "John Quincy Adams"
presidents.each {|i| print i, "\n"}
print "\n"

The preceding code produces this output:
[slitt@mydesk slitt]$ ./array.rb
nil
nil
Adams
nil
Madison
nil
Adams
=======================
nil
nil
Adams
nil
Madison
nil
John Quincy Adams

[slitt@mydesk slitt]$

The length of the array is the determined by the last initialized element, even if that element was initialized to nil. That can be very tricky, especially because if you read past the end of the array it returns nil. Be careful.

You can insert an element by assignment, as shown in the preceding code. If you assign to an element that already exists, you simply change its value, as we changed "Adams" to "John Quincy Adams".

Another thing you can do is get a slice of an array.
#!/usr/bin/ruby
presidents = ["Ford", "Carter", "Reagan", "Bush1", "Clinton", "Bush2"]
p123=presidents[1..3]
p123.each { |i| print i, "\n"}

Notice this time I used the two period version of the elipses operator, so you'd expect it to list Carter, Reagan and Bush1, and indeed it does. The preceding slice produces the following output:
[slitt@mydesk slitt]$ ./array.rb
Carter
Reagan
Bush1
[slitt@mydesk slitt]$

Another way to slice an array is with a start and a count instead of a range. The following is another way to write basically the same code as the preceding code:
#!/usr/bin/ruby
presidents = ["Ford", "Carter", "Reagan", "Bush1", "Clinton", "Bush2"]
p123=presidents[1,3]
p123.each { |i| print i, "\n"}

The preceding used a starting subscript of 1 and a count of 3, instead of a range 1 through 3.

You can also use slices in insertions, deletions and replacements, and you can insert/replace with elements or whole arrays. Our first example deletes unneeded elements from the middle of an array:
#!/usr/bin/ruby
numbers = ["one", "two", "buckle", "my", "shoe", "three", "four"]
numbers.each { |i| print i, "\n"}
print "=====================\n"
numbers[2,3]=[]
numbers.each { |i| print i, "\n"}

In the preceding, we have extraneous elements "buckle", "my" and "shoe", which we want to delete. So we replace element 2, for a count of 4 (element 2 and the next 2, in other words), to an empty array, effectively deleting them. The result follows:

[slitt@mydesk slitt]$ ./array.rb
one
two
buckle
my
shoe
three
four
=====================
one
two
three
four
[slitt@mydesk slitt]$

Next, let's replace three numeric representations with their spelled out equivalents, plus add in another element we had forgotten:
#!/usr/bin/ruby
numbers = ["one", "two", "3", "4", "5", "seven"]
numbers.each { |i| print i, "\n"}
print "=====================\n"
numbers[2,3]=["three", "four", "five", "six"]
numbers.each { |i| print i, "\n"}

You can see we deleted the three numerics, and then added the four spelled out versions in their place. Here's the output:
[slitt@mydesk slitt]$ ./array.rb
one
two
3
4
5
seven
=====================
one
two
three
four
five
six
seven
[slitt@mydesk slitt]$

But what if you don't want to replace anything -- what if you just want to insert in the middle? No problem -- use 0 for the count...
#!/usr/bin/ruby
numbers = ["one", "two", "five"]
numbers.each { |i| print i, "\n"}
print "=====================\n"
numbers[2,0]=["three", "four"]
numbers.each { |i| print i, "\n"}

The only trick here is that if you are not deleting the starting point element, the insertion will occur AFTER the starting element. Here is the output:
[slitt@mydesk slitt]$ ./array.rb
one
two
five
=====================
one
two
three
four
five
[slitt@mydesk slitt]$

You might ask yourself what to do if you need to append before the first element, given that slice type insertion inserts AFTER the starting point. The simplest answer is to use the unshift method.

You can construct an array using a parenthesized range:

#!/usr/bin/ruby
myArray = (0..9)
myArray.each{|i| puts i}
[slitt@mydesk slitt]$ ./array.rb
0
1
2
3
4
5
6
7
8
9
[slitt@mydesk slitt]$

Finally, remembering that Ruby is intended to be an object oriented language, let's look at some of the more common methods associated with arrays (which are really objects in Ruby):
#!/usr/bin/ruby
numbers = Array.new
numbers[3] = "three"
numbers[4] = nil
print "Class=", numbers.class, "\n"
print "Length=", numbers.length, "\n"
numbers.each { |i| print i, "\n"}

The Array.new method types numbers as an array. You could have done the same thing with numbers=[]. The next line assigns text three to the element with subscript 3, thereby setting the element and also setting the array's length. The next line sets the element whose subscript is 4 to nil, which, when you view the output, will prove that the length method returns one plus the last initialized element, even if it's initialized to nil. This, in my opinion, could cause trouble.

The class method returns the variable's class, which in a non-oop language could be thought of as its type. The following is the output:
[slitt@mydesk slitt]$ ./hello.rb
Class=Array
Length=5
nil
nil
nil
three
nil
[slitt@mydesk slitt]$

We've gone through arrays in great detail, because you'll use them regularly. Now it's time to review Ruby's other built in container class...
Hashes
There are two ways to think of a hash:
1. A set of key->value pairs
2. An array whose subscripts aren't necessarily ordered or numeric
Both of the preceding are correct, and do not conflict with each other.
#!/usr/bin/ruby
litt = {"lname"=>"Litt", "fname"=>"Steve", "ssno"=>"123456789"}
print "Lastname : ", litt["lname"], "\n"
print "Firstname : ", litt["lname"], "\n"
print "Social Security Number: ", litt["ssno"], "\n"
print "\n"
litt["gender"] = "male"
litt["ssno"] = "987654321"
print "Corrected Social Security Number: ", litt["ssno"], "\n"
print "Gender : ", litt["gender"], "\n"
print "\n"
print "Hash length is ", litt.length, "\n"
print "Hash class is ", litt.class, "\n"

In the preceding, we initialized the hash with three elements whose keys were lname, fname and ssno. We later added a fourth element whose key was gender, as well as correcting the value of ssno. The class and length methods do just what we'd expect, given our experience from arrays. This hash could be thought of as a single row in a database table. Here is the result:
[slitt@mydesk slitt]$ ./hash.rb
Lastname : Litt
Firstname : Litt
Social Security Number: 123456789

Corrected Social Security Number: 987654321
Gender : male

Hash length is 4
Hash class is Hash
[slitt@mydesk slitt]$


Better yet, hashes values can be other types of classes. For instance, consider a hash of hashes:
#!/usr/bin/ruby
people = {
"torvalds"=>{"lname"=>"Torvalds", "fname"=>"Linus", "job"=>"maintainer"},
"matsumoto"=>{"lname"=>"Matsumoto", "fname"=>"Yukihiro", "job"=>"Ruby originator"},
"litt"=>{"lname"=>"Litt", "fname"=>"Steve", "job"=>"troubleshooter"}
}

keys = people.keys

for key in 0...keys.length
print "key : ", keys[key], "\n"
print "lname: ", people[keys[key]]["lname"], "\n"
print "fname: ", people[keys[key]]["fname"], "\n"
print "job : ", people[keys[key]]["job"], "\n"
print "\n\n"
end

Here's the output:
[slitt@mydesk slitt]$ ./hash.rb
key : litt
lname: Litt
fname: Steve
job : troubleshooter


key : matsumoto
lname: Matsumoto
fname: Yukihiro
job : Ruby originator


key : torvalds
lname: Torvalds
fname: Linus
job : maintainer


[slitt@mydesk slitt]$

Basically, you just implemented the equivalent of a database table, whose rows correspond to Litt, Matsumoto and Torvalds, and whose columns are lname, fname and job. There are probably a dozen better ways to actually print this information, but at this point I'm still learning Ruby, so I did it with a distinctively Perl accent. Perhaps that's a good thing -- it proves that Ruby follows ordinary programming logic in addition to its many wonderful features.
Sorting Hashes
You sort hashes by converting them to 2 dimensional arrays -- an array of key/value pairs, and then sorting them. The sort method does just that. Here's an example:
#!/usr/bin/ruby -w

h = Hash.new
h['size'] = 'big'
h['color'] = 'red'
h['brand'] = 'ford'

av = h.sort{|a,b| a[1] <=> b[1]}
ak = h.sort{|a,b| a[0] <=> b[0]}
ak.each do
|pair|
print pair[0]
print "=>"
print pair[1]
puts
end
puts "=============="
av.each do
|pair|
print pair[0]
print "=>"
print pair[1]
puts
end [slitt@mydesk ~]$ ./test.rb
brand=>ford
color=>red
size=>big
==============
size=>big
brand=>ford
color=>red
[slitt@mydesk ~]$ Notice that often a simple <=> command does not suffice, and you actually need to write your own function to establish collation order. Simply write a function taking two arguments (a and b) that returns 1 when a is superior to b, -1 when a is inferior to b, and 0 when they are equivalent.
Tests and Info Requests on Hashes
Method What it does Synonyms
has_key?(key) Tests whether the key is present in the hash. include?(key), key?(key) and member?(key)
has_value?(value) Tests whether any element of the hash has the value, returning true or false. value?(value)
index(value) Returns the key for an element with the value. I don't know what happens if multiple elements have that value.
select {|key, value| block} => array Returns an array of key/value pairs for which block evaluates true:
h.select {|k,v| v < 200} empty? Returns True if no key/value pairs inspect Return contents of the hash as a string invert Returns a new hash with keys and values switched. length How many key/value pairs does it have? size() sort {| a, b | block } => array


Strings
Strings are a class that ship with Ruby. The String class has a huge number of methods, such that memorizing them all would be futile. If you really want a list of them all, go http://www.rubycentral.com/book/ref_c_string.html., but don't say I didn't warn you.

What I'd like to do here is give you the 10% of strings you'll need for 90% of your work. By the way, Ruby has regular expressions, and that will be covered in the following section. This section covers only Ruby's String class methods.

Let's start with string assignment and concatination:
#!/usr/bin/ruby
myname = "Steve Lit"
myname_copy = myname
print "myname = ", myname, "\n"
print "myname_copy = ", myname_copy, "\n"
print "\n=========================\n"
myname << "t" print "myname = ", myname, "\n" print "myname_copy = ", myname_copy, "\n" The double less than sign is a Ruby String overload for concatination. If all goes well, we'll change the original string but the copy won't change. Let's verify that: [slitt@mydesk slitt]$ ./string.rb myname = Steve Lit myname_copy = Steve Lit ========================= myname = Steve Litt myname_copy = Steve Litt [slitt@mydesk slitt]$ Oh, oh, it changed them both. String assignment copies by reference, not by value. Do you think that might mess up your loop break logic? Use the String.new() method instead: #!/usr/bin/ruby myname = "Steve Lit" myname_copy = String.new(myname) print "myname = ", myname, "\n" print "myname_copy = ", myname_copy, "\n" print "\n=========================\n" myname << "t" print "myname = ", myname, "\n" print "myname_copy = ", myname_copy, "\n" Here's the proof that it works the way you want it: [slitt@mydesk slitt]$ ./hello.rb myname = Steve Lit myname_copy = Steve Lit ========================= myname = Steve Litt myname_copy = Steve Lit [slitt@mydesk slitt]$ One really nice thing about the Ruby String class is it works like an array of characters with respect to splicing: #!/usr/bin/ruby myname = "Steve was here" print myname[6, 3], "\n" myname[6, 3] = "is" print myname, "\n" [slitt@mydesk slitt]$ ./string.rb was Steve is here [slitt@mydesk slitt]$ This gets more powerful when you introduce the index string method, which returns the subscript of the first occurrence of a substring: #!/usr/bin/ruby mystring = "Steve was here" print mystring, "\n" substring = "was" start_ss = mystring.index(substring) mystring[start_ss, substring.length] = "is" print mystring, "\n" In the preceding, the start point for replacement was the return from the index method, and the count to replace is the return from the length method (on the search text). The result is a generic replacement: [slitt@mydesk slitt]$ ./string.rb Steve was here Steve is here [slitt@mydesk slitt]$ Naturally, in real life you'd need to add code to handle cases where the search string wasn't found. You already saw in-place concatenation with the << method, but in addition there's the more standard plus sign concatenation: #!/usr/bin/ruby mystring = "Steve" + " " + "was" + " " + "here" print mystring, "\n" [slitt@mydesk slitt]$ ./string.rb Steve was here [slitt@mydesk slitt]$ If the addition sign means to add strings together, it's natural that the multiplication sign means string together multiple copies: #!/usr/bin/ruby mystring = "Cool " * 3 print mystring, "\n" [slitt@mydesk slitt]$ ./string.rb Cool Cool Cool [slitt@mydesk slitt]$ Do you like the sprintf() command in C? Use the % method in Ruby: #!/usr/bin/ruby mystring = "There are %6d people in %s" % [1500, "the Grand Ballroom"] print mystring, "\n [slitt@mydesk slitt]$ ./string.rb There are 1500 people in the Grand Ballroom [slitt@mydesk slitt]$ You can compare strings: #!/usr/bin/ruby print "frank" <=> "frank", "\n"
print "frank" <=> "fred", "\n"
print "frank" <=> "FRANK", "\n"
[slitt@mydesk slitt]$ ./hello.rb
0
-1
1
[slitt@mydesk slitt]$

Here are some other handy string methods:

mystring.capitalize Title case. Returns new string equal to mystring except that the first letter of every word is uppercase
mystring.capitalize! Title case in place.
mystring.center(mynumber) Returns a new string mynumber long with mystring centered within it. If mynumber is already less than the length of mystring, returns a copy of mystring.
mystring.chomp Returns a new string equal to mystring except any newlines at the end are deleted. If chomp has an argument, that argument serves as the record separator, replacing the default newline.
mystring.chomp! Same as chomp, but in place. Equivalent of Perl chomp().
mystring.downcase Returns new string equal to mystring but entirely lower case.
mystring.downcase! In place modifies mystring, making everything lower case.
mystring.reverse Returns new string with all characters reversed. IOWA becomes AWOI.
mystring.reverse! Reverses mystring in place.
mystring.rindex(substring) Returns the subscript of the last occurrence of the substring. Like index except that it returns the last instead of first occurrence. This method actually has more options, so you might want to read the documentation.
mystring.rjust(mynumber) Returns a copy of mystring, except the new copy is mynumber long, and mystring is right justified in that string. If mynumber is smaller than the original length of mystring, it returns an exact copy of mystring.
mystring.split(pattern, limit) Returns a new array with parts of the string split wherever pattern was encountered as a substring. If limit is given, returns at most that many elements in the array.
mystring.strip Returns a new string that is a copy of mystring except all leading and trailing whitespace have been removed.
mystring.to_f Returns the floating point number represented by mystring. Returns 0.0 if it's not a valid number, and never raises exceptions. Careful!
mystring.to_i Returns an integer represented by mystring. Non-numerics at the end are ignored. Returns 0 on invalid numbers, and never raises exceptions. Careful!
mystring.upcase Returns a new string that's an uppercase version of mystring.
mystring.upcase! Uppercases mystring in place.



There are many, many more methods, but the preceding should get you through most programming tasks. If you end up using Ruby a lot, it would help to learn all the methods.

A word about mystring.split(pattern). What about the reverse -- turning an array into a string? Try this:
#!/usr/bin/ruby
mystring=""
presidents = ["reagan", "bush1", "clinton", "bush2"]
presidents.each {|i| mystring << i+" "}
mystring.strip
print mystring, "\n"
[slitt@mydesk slitt]$ ./string.rb
reagan bush1 clinton bush2
[slitt@mydesk slitt]$

Here's a version that turns it into a comma delimited file with quotes:
#!/usr/bin/ruby
mystring=""
presidents = ["reagan", "bush1", "clinton", "bush2"]
presidents.each {|i| mystring << "\"" + i + "\", "}
mystring[mystring.rindex(", "), 2] = ""
print mystring, "\n"
[slitt@mydesk slitt]$ ./string.rb
"reagan", "bush1", "clinton", "bush2"
[slitt@mydesk slitt]$

You now know most of the Ruby string techniques you need for the majority of your work. Well, except for regular expressions, of course...
Regular Expressions

NOTE

This section assumes you understand the concept of regular expressions. If you do not, there are many fine regular expression tutorials on the web, including this one on my Litt's Perls of Wisdom subsite.

Regular expressions make life so easy, often replacing 100 lines of code with 5. Perl is famous for its easy to use and intuitive regular expressions.

Ruby is a little harder because most regular expression functionality is achieved by a regular expression object that must be instantiated. However, you CAN test for a match the same as in Perl:
#!/usr/bin/ruby
string1 = "Steve was here"
print "e.*e found", "\n" if string1 =~ /e.*e/
print "Sh.*e found", "\n" if string1 =~ /Sh.*e/
[slitt@mydesk slitt]$ ./regex.rb
e.*e found
[slitt@mydesk slitt]$


Here's the code to actually retrieve the first match of /w.ll/ in the string:
#!/usr/bin/ruby
string1 = "I will drill for a well in walla walla washington."
if string1 =~ /(w.ll)/
print "Matched on ", $1, "\n"
else
puts "NO MATCH"
end
[slitt@mydesk slitt]$ ./regex.rb
Matched on will
[slitt@mydesk slitt]$

This was almost just like Perl. You put parentheses in the regular expression to make a group, perform the regular expression search with the =~ operator, and then the match for the group is contained in the $1 variable. If there had been multiple groups in the regular expressions, matches would have also been available in $2, $3, and so on, up to the number of groups in the regular expression.


The more OOPish method of doing all this is to instantiate a new Regexp object and using its methods to gain the necessary information:
#!/usr/bin/ruby
string1 = "I will drill for a well in walla walla washington."
regex = Regexp.new(/w.ll/)
matchdata = regex.match(string1)
if matchdata
puts matchdata[0]
puts matchdata[1]
else
puts "NO MATCH"
end

[slitt@mydesk slitt]$ ./hello.rb
will
nil
[slitt@mydesk slitt]$

If you change /w.ll/ to /z.ll/, which of course does not match because there's not a "z" in string1, the output looks like this:

[slitt@mydesk slitt]$ ./hello.rb
NO MATCH
[slitt@mydesk slitt]$
The preceding example shows how to do complete regex in Ruby. Start by creating a regular expression object using Regexp.new(). Then use that object's match method to find a match and return it in a MatchData object. Test that the MatchData object exists, and if it does, get the first match (matchdata[0]). The reason we also printed matchdata[1] was to show that, in the absense of groups surrounded by parentheses, the match method returns only a single match. Later you'll see a special way to return all matches of a single regular expression.

Another thing to notice is that, in Ruby, matching is not greedy by default. It finds the shortest string that satisfies the regular expression. If Ruby's matching was greedy like Perl's, the match would have included the entire string:

"will drill for a well in walla wall"

In other words, it would have returned everything from the first w to the last double l. Ungreedy matches go along with Ruby's principle of least surprise, but sometimes what you want is greedy matching.

You can return several matches using multiple groups, like this:
#!/usr/bin/ruby
string1 = "I will drill for a well in walla walla washington."
regex = Regexp.new(/(w.ll).*(in).*(w.ll)/)
matchdata = regex.match(string1)
if matchdata
for ss in 0...matchdata.length
puts matchdata[ss]
end
else
puts "NO MATCH"
end
[slitt@mydesk slitt]$ ./hello.rb
will drill for a well in walla wall
will
in
wall
[slitt@mydesk slitt]$

Note the different behavior when you use parentheses. Here you see that the 0 subscript element matches the entire regular expression, while elements 1, 2 and 3 are the individual matches for the first, second and third parenthesized groups.

What if you wanted to find ALL the matches for /w.ll/ in the string, without guessing beforehand how many parentheses to put in? Here's the way you do it:
#!/usr/bin/ruby
string1 = "I will drill for a well in walla walla washington."
regex = Regexp.new(/w.ll/)
matchdata = regex.match(string1)
while matchdata != nil
puts matchdata[0]
string1 = matchdata.post_match
matchdata = regex.match(string1)
end
[slitt@mydesk slitt]$ ./regex.rb
will
well
wall
wall
[slitt@mydesk slitt]$

What you've done here is repeated the match, over and over again, each time assigning the remainder of the string after the match to string1 via the post_match method. The loop terminates when no match is found.
Regex Substitution
My research tells me Ruby's regular expressions do not, in and of themselves, have a provision for substitution. From what I've found, you need to use Ruby itself, specifically the String.gsub() method, to actually perform the substitution. If that's true, to me that represents a significant hassle, although certainly not a showstopper. If I'm wrong about this, please let me know.

The following makes all occurrences of /w.ll/ uppercase in the string:
#!/usr/bin/ruby
string1 = "I will drill for a well in walla walla washington."
string1.gsub!(/(w.ll)/){$1.upcase}
puts string1
[slitt@mydesk slitt]$ ./hello.rb
I WILL drill for a WELL in WALLa WALLa washington.
[slitt@mydesk slitt]$

The preceding depends on the block form of the String.gsub() method. I could not get the non-block form to accept the matches of the regular expression.

If you had wanted to replace only the first occurrence of /w.ll/, you would have had to do this (warning, ugly!):
#!/usr/bin/ruby
puts string1
regex = Regexp.new(/w.ll/)
match = regex.match(string1)
offsets = match.offset(0)
startOfMatch = offsets[0]
endOfMatch = offsets[1]
string1[startOfMatch...endOfMatch] = match[0].upcase
puts string1
[slitt@mydesk slitt]$ ./regex.rb
I WILL drill for a well in walla walla washington.
[slitt@mydesk slitt]$

Being a Perl guy, I'm used to having the regular expression do the entire substitution in a single line of code, and find the preceding quite cumbersome. Obviously, some of the preceding code was inserted just for readability. For instance, I could have done this:
#!/usr/bin/ruby
string1 = "I will drill for a well in walla walla washington."
match = /w.ll/.match(string1)
string1[match.offset(0)[0]...match.offset(0)[1]] = match[0].upcase
puts string1

Or even this, which I'm sure would have fit right in with K&R first edition:
#!/usr/bin/ruby
string1 = "I will drill for a well in walla walla washington."
match = /w.ll/.match(string1)
string1[/w.ll/.match(string1).offset(0)[0].../w.ll/.match(string1).offset(0)[1]] = match[0].upcase
puts string1

If you can read the preceding, you're a better programmer than I.

In my opinion, Ruby beats the daylights out of Perl in most aspects, but not in regular expressions.

No comments:

Post a Comment