tags:

views:

491

answers:

8

How do you write a regular expression that matches a numeric range from 0 or 000 to 180 ?

+1  A: 

Try this:

^(0|[1-9][0-9]?|1[0-7][0-9]|180)$
Gumbo
This does not work for input of single digit, which I belive should be allowed.
Stevo3000
@Stevo3000: Fixed it.
Gumbo
Neither for a triple `000`.
Ionuț G. Stan
@Ionut G. Stan: I think that’s just the alternative if matching just numbers with no leading zeros is too difficult.
Gumbo
+14  A: 

I don't think regex is the right choice for this. Have you tried parsing the value? If you have to use regex I would match \d{1,3} parse the string and then validate the number in code.

Stevo3000
+1 The other answers had at least one bug each, that's why it's not worth using RE for these tasks.
soulmerge
Two bugs even :( but yes, I fundamentally agree.
Joey
In every other context it might have been easier to parse a value, but it's used in a larger regex which passes a coordinate like 54°11'56.234''
Morten
Well, in that case capture each individual part of the coordinate in a capture group and validate them afterwards.
Joey
This is the right answer in my opinion. People who try to solve these thing with pure REs are doing themselves (and the people that come after them) a disservice.
paxdiablo
+8  A: 

The easiest way for this would be to parse the string as a number and look for the number to be in the proper range.

To do this with pure regex you need to identify the pattern and write it out:

^(0?[0-9]{1,2}|1[0-7][0-9]|180)$

This has three alternatives: one for single- and two-digit numbers (allowing leading zeroes), where each digit can be anything from 0 to 9. And another one that specifies what range of digits is allowed for each digit in a three-digit number. In this case, this means that the first digit needs to be 1, the second between 0 and 7 and the last one may be anything. The third alternative is just for the number 180 which didn't fit nicely into the pattern elsewhere.

A more straightforward approach might be

^(0{0,2}[0-9]|0?[1-9][0-9]|1[0-7][0-9]|180)$

which just alternates for each tricky numeric range there might be.

Joey
This does the trick. As you also mentioned it has to match 3 digit numbers as 001, 010, 012 and so on which this does. Thank you!
Morten
A: 

I modified Gumbo's:

^(00?0?|0?[1-9][0-9]?|1[0-7][0-9]|180)$

Try that.

Robert L
A: 

if you don't care about negative numbers

>> r = /\b(0?\d?\d|1[0-7]\d|180)\b/
=> /\b(0?\d?\d|1[0-7]\d|180)\b/
>> (0..200).map {|i| i.to_s =~ r }
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
>>
neoneye
+4  A: 

There is an online utility to generate these at UtilityMill.com For your question, this returns:

0*([0-9]{1,2}|1[0-7][0-9]|180)
Paul McGuire
As a general rule, I wouldn't trust a regex written by a program. My experiences with RegexBuddy have shown that it is not my "buddy," nor can it write decent regular expressions.
Chris Lutz
This one is correct, though. Although it allows for arbitrarily many leading zeros.
Joey
A: 

I would break down the ranges so that it can easily be specified in separate individual regex:

^(0|0[0-9][0-9]|1[0-7][0-9]|180)$

Or, what's the same in human readable terms:

0
000-099
100-179
180

If you need the two digit range, it's just a matter of adding [0-9][0-9] to the regex.

Also, if you are having trouble working with regex, try to specify them in a manner that makes the regex operators as clear as possible - usually there's a way to represent them in a way that makes their function much more clear, specially if the language you are doing this in allows you to separate portions of the regex specification into separate columns and lines..

lcv
You forgot single digit 1 to 9.
Robert L
No, I just read "0 or 000 to 180" and interpreted to mean: 0 as one digit, or the range 000 to 180 as three digits. When I said "If you need the two digit range..." I should have also mentioned the one digit range, so in regards to that you are correct.
lcv
+1  A: 

My two cents:

Anyone posting an answer to this question should have tested their regex with AT LEAST the following inputs:

Should match: 0, 00, 000, 5, 05, 005, 95, 095, 180

Should NOT match: 0000, 0095, 181, 190

I think what Johannes Rössel wrote is about as good as you'll get:

^(0?[0-9]{1,2}|1[0-7][0-9]|180)$
jnylen
PowerShell helps for validating: `-20..200|%{$_;"{0:00}"-f$_;"{0:000}"-f$_}|%{if ($_-match"^(0?[0-9]{1,2}|1[0-7][0-9]|180)$"){Write-Host -fore green $_}else{Write-Host -fore red $_}}`
Joey