views:

49

answers:

4
price:(?:(?:\d+)?(?:\.)?\d+|min)-?(?:(?:\d+)?(?:\.)?\d+|max)?

This Regex matches the following examples correctly.

price:1.00-342
price:.1-23
price:4
price:min-900.00
price:.10-.50
price:45-100
price:453.23-231231
price:min-max

Now I want to improve it to match these cases.

price:4.45-8.00;10.45-14.50
price:1.00-max;3-12;23.34-12.19
price:1.00-2.50;min-12;23.34-max

Currently the match stops at the semi colon. How can I get the regex to repeat across the semi-colon dividers?

Final Solution:

price:(((\d*\.)?\d+|min)-?((\d*\.)?\d+|max)?;?)+
+1  A: 

First there are some issues with your regular expression: to match xx.yyy instead of the expression (?:\d+)?(?:\.)?\d+ you can use this (?:\d*\.)?\d+. This can only match in one way so it avoids unnecessary backtracking.

Also currently your regular expression matches things like price:minmax and price:1.2.3 which I assume you do not want to match.

The simple way to repeat your match is to add a semi-colon and then repeat your regular expression verbatim.

You can do it like this though to avoid writing out the entire regular twice:

price:(?:(?:(?:\d*\.)?\d+|min)(?:-(?:(?:\d*\.)?\d+|max))?(?:;|$))*

See it in action on Rubular.

Mark Byers
Why can't he just say "or more of these"?
zebediah49
@zebediah49: Because there is no syntax in regular expressions for "add a separator then do the same again". :(
Mark Byers
@Mark: `(?:<something>(?:<sep>|$))+` ?
Amber
@Amber: I've totally rewritten the regular expression - I hope you'll agree that it's much cleaner (and more correct!) now. Let me know if you find further improvements.
Mark Byers
A: 
price:((?:(?:\d+)?(?:\.)?\d+|min)-?(?:(?:\d+)?(?:\.)?\d+|max)?;?)+

I'm not sure what's up with all of the ?'s (I know the syntax, I just don't know why you're using it so much), but that should do it for you.

zebediah49
Just a note: For the string 'price:min-maxmax' this matches 'price:min-max' which might or might not be what the OP wants (he didn't specify).
Mark Byers
+1  A: 

Add an optional ; at the end, and make the whole pattern to match one or more:

price:((?:(?:\d+)?(?:\.)?\d+|min)-?(?:(?:\d+)?(?:\.)?\d+|max)?;?)+

Vinko Vrsalovic
Just what I was looking for. Thanks!
Arron
+1  A: 

(?:\d+)? is the same thing as \d*, and (?:\.)? can just be \.?. Simplified, your original regex is:

price:(?:\d*\.?\d+|min)(?:-(?:\d*\.?\d+|max))?

You have two choices. You can either do price([:;]range)* where range is the regex you have for matching number ranges, or be more precise about the punctuation but have to write out range twice and do price:range(;range)*.

price([:;]range)*      -- shorter but allows first ':' to be ';'
price:range(;range)*   -- longer but gets colon vs semi-colon correct

Pick one of these two regexes:

price[:;](?:\d*\.?\d+|min)(?:-(?:\d*\.?\d+|max))?
price:(?:\d*\.?\d+|min)(?:-(?:\d*\.?\d+|max))?(?:(?:\d*\.?\d+|min)(?:-(?:\d*\.?\d+|max))?)*
John Kugelman