Regexp exercise

Hi,
I have a string from which I want to extract a value. I have found four
different methods to do it:

string = "a: 1, b: 2, c: 3"
# let's say I want the value associated with b (2)

# 1st method:
value = string[/b: \d+/][/\d+/]

# 2nd method:
value = string.scan(/b: (\d+)/)[0][0]

# 3rd method:
value = nil
string.scan(/b: (\d+)/) { |val| value = val }

These three methods aren't clean and easy to understand.

I think that the best way to do it would be to use a simple match
operator like:
value = $1 if string =~ /b: (\d+)/

But on a different thread (http://tinyurl.com/38b27) someone explained
that using global variables was a bad habit not to take.

What should I do? Is the $1 method *that* bad? (after all, I just use it
inside the 'if' loop...)

···

--
Olivier D.

["Olivier D." <nkh@SP_tele2_AM.fr>, 2004-07-07 14.37 CEST]

Hi,
I have a string from which I want to extract a value. I have found four
different methods to do it:

string = "a: 1, b: 2, c: 3"
# let's say I want the value associated with b (2)

# 1st method:
value = string[/b: \d+/][/\d+/]

# 2nd method:
value = string.scan(/b: (\d+)/)[0][0]

# 3rd method:
value = nil
string.scan(/b: (\d+)/) { |val| value = val }

These three methods aren't clean and easy to understand.

I think that the best way to do it would be to use a simple match
operator like:
value = $1 if string =~ /b: (\d+)/

But on a different thread (http://tinyurl.com/38b27\) someone explained
that using global variables was a bad habit not to take.

What should I do? Is the $1 method *that* bad? (after all, I just use it
inside the 'if' loop...)

I don't find it bad, but if you want to avoid it you can do

  matchdata=/b: (\d+)/.match(string) and value=matchdata[1]

value = string[/b: \d+/][/\d+/]

   value = string[/b: (\d+)/, 1]

Guy Decoux

Hi --

Hi,
I have a string from which I want to extract a value. I have found four
different methods to do it:

string = "a: 1, b: 2, c: 3"
# let's say I want the value associated with b (2)

# 1st method:
value = string[/b: \d+/][/\d+/]

# 2nd method:
value = string.scan(/b: (\d+)/)[0][0]

# 3rd method:
value = nil
string.scan(/b: (\d+)/) { |val| value = val }

These three methods aren't clean and easy to understand.

I think that the best way to do it would be to use a simple match
operator like:
value = $1 if string =~ /b: (\d+)/

In addition to the other answers, if you want to grab the value as an
integer, you could do:

  require 'scanf'
  str = "a: 1, b: 2, c: 3"
  val, = str.scanf("%*[^b]b: %d")
  p val # => 2

David

···

On Wed, 7 Jul 2004, Olivier D. wrote:

--
David A. Black
dblack@wobblini.net

Olivier D. wrote:

I think that the best way to do it would be to use a simple match
operator like:
value = $1 if string =~ /b: (\d+)/

But on a different thread (http://tinyurl.com/38b27\) someone explained
that using global variables was a bad habit not to take.

I'm not 100% but as far as I remember $1 is thread local, i.e. no two threads can interfere with each other if they match regular expressions at the same time. In that case it would be save to use $1. Can anybod comment on that?

Kind regards

  robert

Thanks for the advice. It's just that it took me two days to remember
that the groups of a pattern are put in $1..$9 with the =~ operator.

I discovered that $1 can have two different values:
- nil if a number is not found
- the number found if it exists
Which means: no errors possible from a previous match. $1 has his value
changed every time.

···

On 2004-07-07, Carlos <angus@quovadis.com.ar> wrote:

["Olivier D." <nkh@SP_tele2_AM.fr>, 2004-07-07 14.37 CEST]

What should I do? Is the $1 method *that* bad? (after all, I just use it
inside the 'if' loop...)

I don't find it bad, but if you want to avoid it you can do

  matchdata=/b: (\d+)/.match(string) and value=matchdata[1]

--
Olivier D.

Wonderful, exactly the "hacker's way" I was looking for.
This feature is not on the (rather old) documentation I was looking at.
I think it's time for me to dig into Ruby's source code...

···

On 2004-07-07, ts <decoux@moulon.inra.fr> wrote:

value = string[/b: \d+/][/\d+/]

   value = string[/b: (\d+)/, 1]

Guy Decoux

--
Olivier D.

Hi --

···

On Wed, 7 Jul 2004, Olivier D. wrote:

On 2004-07-07, ts <decoux@moulon.inra.fr> wrote:

>
>> value = string[/b: \d+/][/\d+/]
>
> value = string[/b: (\d+)/, 1]
>
> Guy Decoux

Wonderful, exactly the "hacker's way" I was looking for.
This feature is not on the (rather old) documentation I was looking at.
I think it's time for me to dig into Ruby's source code...

You'll find this documented in ri. (Not that I want to discourage you
from looking at the source too :slight_smile:

David

--
David A. Black
dblack@wobblini.net