# Strange behavior of String.scan

**URL:** <https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210>\
**Category:** Ruby\
**Created:** [May 27, 2007, 9:55am UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210 "2007-05-27T09:55:37Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![HSSSSvard\_Moen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/b19c9b/32.png) [@HSSSSvard\_Moen](https://www.ruby-forum.com/u/HSSSSvard_Moen)\
**Post date:** [May 27, 2007, 9:55am UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210/1 "2007-05-27T09:55:37Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![HSSSSvard\_Moen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/b19c9b/32.png) [@HSSSSvard\_Moen](https://www.ruby-forum.com/u/HSSSSvard_Moen)\
**Post date:** [May 27, 2007, 10:17am UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210/2 "2007-05-27T10:17:39Z")

</div>

HÃ¥vard Moen wrote:

> 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”]

---

<div class="post-metadata">

**Author:** ![HSSSSvard\_Moen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/b19c9b/32.png) [@HSSSSvard\_Moen](https://www.ruby-forum.com/u/HSSSSvard_Moen)\
**Post date:** [May 27, 2007, 10:46am UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210/3 "2007-05-27T10:46:40Z")

</div>

Alex Y. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > puts monitor.inspect  
> > “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?

---

<div class="post-metadata">

**Author:** ![HSSSSvard\_Moen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/b19c9b/32.png) [@HSSSSvard\_Moen](https://www.ruby-forum.com/u/HSSSSvard_Moen)\
**Post date:** [May 27, 2007, 11:21am UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210/4 "2007-05-27T11:21:44Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![HSSSSvard\_Moen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/b19c9b/32.png) [@HSSSSvard\_Moen](https://www.ruby-forum.com/u/HSSSSvard_Moen)\
**Post date:** [May 27, 2007, 11:45am UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210/5 "2007-05-27T11:45:49Z")

</div>

Daniel DeLorme [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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

Great, thanks.

---

<div class="post-metadata">

**Author:** ![HSSSSvard\_Moen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/b19c9b/32.png) [@HSSSSvard\_Moen](https://www.ruby-forum.com/u/HSSSSvard_Moen)\
**Post date:** [May 27, 2007, 11:25am UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210/6 "2007-05-27T11:25:44Z")

</div>

On 27.05.2007 10:17, Alex Y. wrote:

> > puts monitor.inspect  
> > “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”]

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

---

<div class="post-metadata">

**Author:** ![HSSSSvard\_Moen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/b19c9b/32.png) [@HSSSSvard\_Moen](https://www.ruby-forum.com/u/HSSSSvard_Moen)\
**Post date:** [May 27, 2007, 1:26pm UTC](https://www.ruby-forum.com/t/strange-behavior-of-string-scan/105210/7 "2007-05-27T13:26:00Z")

</div>

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

> > > data.scan(/monitor all (.\*)$/) do |monitor|  
> > > “192.168.1.68”
> 
> Ok, but is there a way to get just the string without using something  
> like monitor = monitor[0] at the start of the block?

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. 🙂

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
