Strange behavior of String.scan

When I use String.scan with a block and just one group the result ends
up as an array. More than one group works as expected. A small example to
demonstrate:

--ruby code start--
data = ' lb method member observed
   monitor all http
   member 192.168.1.68:http'
data.scan(/monitor all (.*)$/) do |monitor|
  puts monitor.inspect
end
data.scan(/member ([0-9.]+):(.*)/) do |adress, port|
  puts adress.inspect
  puts port.inspect
end
--ruby code end--

gives me:
["http"]
"192.168.1.68"
"http"

I'm running:
ruby 1.8.6 (2007-03-13 patchlevel 0) [i486-linux]

Is there something I have done wrong, or is this a bug?

···

--
Håvard
Laws are like sausages, it is better not to see them being made.
    -- Bismarck

Håvard Moen wrote:

When I use String.scan with a block and just one group the result ends
up as an array. More than one group works as expected. A small example to demonstrate:

--ruby code start--
data = ' lb method member observed
   monitor all http
   member 192.168.1.68:http'
data.scan(/monitor all (.*)$/) do |monitor|
  puts monitor.inspect
end
data.scan(/member ([0-9.]+):(.*)/) do |adress, port|
  puts adress.inspect
  puts port.inspect
end
--ruby code end--

gives me:
["http"]
"192.168.1.68"
"http"

That's expected. What scan actually yields to the block is an array, and in your second example that array is being automatically split into its component parts because you've given more than one block parameter in the pipes. A third example should make it clear:

irb(main):004:0> data.scan(/member ([0-9.]+):(.*)/) do |match|
irb(main):005:1* puts match.inspect
irb(main):006:1> end
["192.168.1.68", "http"]

···

--
Alex

Ok, but is there a way to get just the string without using something
like monitor = monitor[0] at the start of the block?

···

Alex Young <alex@blackkettle.org> wrote:

Håvard Moen wrote:

When I use String.scan with a block and just one group the result ends
up as an array. More than one group works as expected. A small example to
demonstrate:

--ruby code start--
data = ' lb method member observed
   monitor all http
   member 192.168.1.68:http'
data.scan(/monitor all (.*)$/) do |monitor|
  puts monitor.inspect
end
data.scan(/member ([0-9.]+):(.*)/) do |adress, port|
  puts adress.inspect
  puts port.inspect
end
--ruby code end--

gives me:
["http"]
"192.168.1.68"
"http"

That's expected. What scan actually yields to the block is an array,
and in your second example that array is being automatically split into
its component parts because you've given more than one block parameter
in the pipes. A third example should make it clear:

irb(main):004:0> data.scan(/member ([0-9.]+):(.*)/) do |match|
irb(main):005:1* puts match.inspect
irb(main):006:1> end
["192.168.1.68", "http"]

--
Håvard
Laws are like sausages, it is better not to see them being made.
    -- Bismarck

irb(main):001:0> "abc".scan(/abc/) {|m| p m}
"abc"
=> "abc"
irb(main):002:0> "abc".scan(/(a)bc/) {|m| p m}
["a"]
=> "abc"
irb(main):003:0> "abc".scan(/(a)(b)c/) {|m| p m}
["a", "b"]
=> "abc"

  robert

···

On 27.05.2007 10:17, Alex Young wrote:

Håvard Moen wrote:

When I use String.scan with a block and just one group the result ends
up as an array. More than one group works as expected. A small example to demonstrate:

--ruby code start--
data = ' lb method member observed
   monitor all http
   member 192.168.1.68:http'
data.scan(/monitor all (.*)$/) do |monitor|
  puts monitor.inspect
end
data.scan(/member ([0-9.]+):(.*)/) do |adress, port|
  puts adress.inspect
  puts port.inspect
end
--ruby code end--

gives me:
["http"]
"192.168.1.68"
"http"

That's expected. What scan actually yields to the block is an array, and in your second example that array is being automatically split into its component parts because you've given more than one block parameter in the pipes. A third example should make it clear:

irb(main):004:0> data.scan(/member ([0-9.]+):(.*)/) do |match|
irb(main):005:1* puts match.inspect
irb(main):006:1> end
["192.168.1.68", "http"]

Håvard Moen wrote:

Ok, but is there a way to get just the string without using something
like monitor = monitor[0] at the start of the block?

You can use a comma to force the array to be parallel-assigned instead of single-assigned:

  data.scan(/monitor all (.*)$/) do |monitor,|
    puts monitor.inspect
  end

Daniel

Use only capturing groups for what you want to capture. For all others use non capturing groups. This sounds trivial but it's actually as easy as that. :slight_smile:

In case you haven't seen non capturing groups yet:

irb(main):002:0> "cababab".scan(/(.)(?:ab)+/) {|m| p m}
["c"]
=> "cababab"

Kind regards

  robert

···

On 27.05.2007 11:44, Håvard Moen wrote:

Alex Young <alex@blackkettle.org> wrote:

Håvard Moen wrote:

When I use String.scan with a block and just one group the result ends
up as an array. More than one group works as expected. A small example to demonstrate:

--ruby code start--
data = ' lb method member observed
   monitor all http
   member 192.168.1.68:http'
data.scan(/monitor all (.*)$/) do |monitor|
  puts monitor.inspect
end
data.scan(/member ([0-9.]+):(.*)/) do |adress, port|
  puts adress.inspect
  puts port.inspect
end
--ruby code end--

gives me:
["http"]
"192.168.1.68"
"http"

That's expected. What scan actually yields to the block is an array, and in your second example that array is being automatically split into its component parts because you've given more than one block parameter in the pipes. A third example should make it clear:

irb(main):004:0> data.scan(/member ([0-9.]+):(.*)/) do |match|
irb(main):005:1* puts match.inspect
irb(main):006:1> end
["192.168.1.68", "http"]

Ok, but is there a way to get just the string without using something
like monitor = monitor[0] at the start of the block?

Great, thanks.

···

Daniel DeLorme <dan-ml@dan42.com> wrote:

Håvard Moen wrote:

Ok, but is there a way to get just the string without using something
like monitor = monitor[0] at the start of the block?

You can use a comma to force the array to be parallel-assigned instead
of single-assigned:

data.scan(/monitor all (.*)$/) do |monitor,|
   puts monitor.inspect
end

--
Håvard
Laws are like sausages, it is better not to see them being made.
    -- Bismarck