# Short question on regex in Ruby

**URL:** <https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587>\
**Category:** Ruby\
**Created:** [September 26, 2008, 4:03pm UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587 "2008-09-26T16:03:24Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![crenner](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/278dde/32.png) [@crenner](https://www.ruby-forum.com/u/crenner)\
**Post date:** [September 26, 2008, 4:03pm UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587/1 "2008-09-26T16:03:24Z")

</div>

Hi,

I have a little problem with a regex in Ruby:

I have twos strings:

string1 = “He is the 20th.”  
string2 = “25th”

I wrote this to “extract” the place (20 or 25 respectively):

place1 = string1.gsub(/._(\d+)th._/,’\1’)  
place2 = string2.gsub(/._(\d+)th._/,’\1’)  
pp place1  
pp place1

=\> “0”  
=\> “5”

Of course, I would like to get all the digits before “th”. Why is only  
the last one captured?

If anyone could please explain this, and help me come up with a regex  
that captures 20 and 25, respectively, this would be greatly  
appreciated.

Cheers, Chris

---

<div class="post-metadata">

**Author:** ![crenner](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/278dde/32.png) [@crenner](https://www.ruby-forum.com/u/crenner)\
**Post date:** [September 26, 2008, 4:16pm UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587/2 "2008-09-26T16:16:21Z")

</div>

On Sep 26, 10:02 am, Chris Ro [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> place1 = string1.gsub(/._(\d+)th._/,‘\1’)  
> place2 = string2.gsub(/._(\d+)th._/,‘\1’)  
> pp place1  
> pp place1
> 
> =\> “0”  
> =\> “5”
> 
> Of course, I would like to get all the digits before “th”. Why is only  
> the last one captured?

Because the .\* is greedy and will get all it can, which is all but the  
last digit.

> If anyone could please explain this, and help me come up with a regex  
> that captures 20 and 25, respectively, this would be greatly

place = string[/\d+(?=th)/]

– Mark.

---

<div class="post-metadata">

**Author:** ![crenner](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/278dde/32.png) [@crenner](https://www.ruby-forum.com/u/crenner)\
**Post date:** [September 26, 2008, 4:23pm UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587/3 "2008-09-26T16:23:41Z")

</div>

Chris Ro wrote:

> place1 = string1.gsub(/._(\d+)th._/,’\1’)

Hello. I think your approach with using gsub is not the best possible  
here. It’s better to simply find the matching part using match and  
substitute it for the whole string, like this:  
place1 = string1.match(/(\d+)th\b/)[1]  
The \b ensures that the next character after ‘th’ is not a word  
character (\b is word boundary), and [1] at the end is extracting the  
first bracketed group. It also makes it possible to skip the .\* at both  
ends, which is a bit ugly.

Apart from that, a useful piece of knowledge about regexps:  
/._?(\d+)th._/ will match what you want, because the first .\*? will be  
reluctant to eat up more characters, so it will pass to \d+ as many  
digits as it can.

TPR.

---

<div class="post-metadata">

**Author:** ![crenner](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/278dde/32.png) [@crenner](https://www.ruby-forum.com/u/crenner)\
**Post date:** [September 26, 2008, 4:30pm UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587/4 "2008-09-26T16:30:27Z")

</div>

2008/9/26 Thomas B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Chris Ro wrote:
> 
> > place1 = string1.gsub(/._(\d+)th._/,‘\1’)
> 
> Hello. I think your approach with using gsub is not the best possible  
> here.

Agree.

> It’s better to simply find the matching part using match and  
> substitute it for the whole string, like this:  
> place1 = string1.match(/(\d+)th\b/)[1]

For extraction there is a simpler solution

irb(main):002:0\> “He is the 20th.”[/(\d+)th\b/, 1]  
=\> “20”  
irb(main):003:0\> “25th”[/(\d+)th\b/, 1]  
=\> “25”

> The \b ensures that the next character after ‘th’ is not a word  
> character (\b is word boundary), and [1] at the end is extracting the  
> first bracketed group. It also makes it possible to skip the .\* at both  
> ends, which is a bit ugly.

Right.

> Apart from that, a useful piece of knowledge about regexps:  
> /._?(\d+)th._/ will match what you want, because the first .\*? will be  
> reluctant to eat up more characters, so it will pass to \d+ as many  
> digits as it can.

But reluctant is slow (see my benchmark from a few days ago).

Cheer

robert

---

<div class="post-metadata">

**Author:** ![crenner](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/278dde/32.png) [@crenner](https://www.ruby-forum.com/u/crenner)\
**Post date:** [September 26, 2008, 5:53pm UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587/5 "2008-09-26T17:53:44Z")

</div>

IMO, lookahead is the best solution for the problem.

---

<div class="post-metadata">

**Author:** ![crenner](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/278dde/32.png) [@crenner](https://www.ruby-forum.com/u/crenner)\
**Post date:** [September 27, 2008, 5:26am UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587/6 "2008-09-27T05:26:42Z")

</div>

If you need to get multiple numbers out you could try scan().

> d=“9,45, 567”  
> =\> “9,45, 567”

> d.scan(/\d+/)  
> =\> [“9”, “45”, “567”]

---

<div class="post-metadata">

**Author:** ![crenner](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/278dde/32.png) [@crenner](https://www.ruby-forum.com/u/crenner)\
**Post date:** [September 26, 2008, 4:44pm UTC](https://www.ruby-forum.com/t/short-question-on-regex-in-ruby/149587/7 "2008-09-26T16:44:24Z")

</div>

Robert K. wrote:

> > It’s better to simply find the matching part using match and  
> > substitute it for the whole string, like this:  
> > place1 = string1.match(/(\d+)th\b/)[1]
> 
> For extraction there is a simpler solution
> 
> irb(main):002:0\> “He is the 20th.”[/(\d+)th\b/, 1]  
> =\> “20”  
> irb(main):003:0\> “25th”[/(\d+)th\b/, 1]  
> =\> “25”

Yes, I forgot about this one. +1

> > Apart from that, a useful piece of knowledge about regexps:  
> > /._?(\d+)th._/ will match what you want, because the first .\*? will be  
> > reluctant to eat up more characters, so it will pass to \d+ as many  
> > digits as it can.
> 
> But reluctant is slow (see my benchmark from a few days ago).

OK. I guess reluctant is slow especially when the string that it has to  
cover is long. And I agree that it’s not a very good idea to use  
reluctant regexps in time-critical applications, and the first solution  
is much better here. I mentioned them just to let the original poster  
gain some knowledge. I use reluctant patterns when not in hurry, because  
they make things much easier sometimes.

TPR.
