2

I have to cut the price from strings like that:

s1 = "somefing $ 100"
s2 = "$       19081 words $"
s3 = "30$"
s4 = "hi $90"
s5 = "wow 150"

Output should be:

s1 = "100"
s2 = "19081"
s3 = "30"
s4 = "90"
s5 = nil

I use the following regex:

price = str[/\$\s*(\d+)|(\d+)\s*\$/, 1]

But it doesn't work for all types of strings.

7
  • See here. Your regex should work. Commented Oct 18, 2015 at 15:49
  • Yeah, I know but I'm getting nil for this string in Ruby: "url 350 $". I don't know how to set new string to data captured in regex. What is the best way to do this? Commented Oct 18, 2015 at 15:50
  • Well, I I copy/paste that in the rubular example it seems to work just fine. Try to post some reproducible example. Commented Oct 18, 2015 at 15:51
  • str[/\$\s*(\d+)|(\d+)\s*\$/, 1] - this does not work. Commented Oct 18, 2015 at 15:52
  • 1
    Top tip: the case your code doesn't work for should be part of the question Commented Oct 18, 2015 at 16:15

3 Answers 3

2

Your code always returns the result of the first capture group group whereas in the failing case it is the second capture group that you are interested in. I don't think the [] method has a good way of dealing with this (when using numbered capture groups). You could write this like so

price = str =~ /\$\s*(\d+)|(\d+)\s*\$/ && ($1 || $2)

Although this isn't very legible. If instead you use a named capture group, then you can do

price = str[/\$\s*(?<amount>\d+)|(?<amount>\d+)\s*\$/, 'amount']

Duplicate named capture groups won't always do what you want but when they are in separate alternation branches (as they are here) then it should work.

Sign up to request clarification or add additional context in comments.

1 Comment

That's it. I knew there's some elegant Ruby way to write conditional for groups :)
1

The problem is that you're always getting value from the first regex group and you don't check the second. So, you're not looking the case after | - the one when digit is before $ sign.

If you look at the graphical representation of your regex, by typing 1 as a second parameter in square brackets, you are covering only the upper path (first case), and you never check lower one (second case).

Basically, try:

price = str[/\$\s*(\d+)|(\d+)\s*\$/, 1] or str[/\$\s*(\d+)|(\d+)\s*\$/, 2]

P.S. I'm not that experienced in Ruby, there might be some more optimal way to type this, but this should do the trick

Comments

-1

try this, its much simpler but it may not be the most efficient.

p1 = s1.gsub(' ','')[/\$(\d+)|(\d+)\$/,1]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.