32

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

Morten
  • 1,819
  • 5
  • 28
  • 37
  • 1
    http://www.regular-expressions.info/numericranges.html is a very useful article – Bergi Mar 14 '13 at 17:13
  • I believe you can use this package `https://github.com/dimka665/range-regex`. It already support negative values. The current code is not updated, so you'll have to download it from that github resource. – swdev Jun 10 '14 at 08:35

9 Answers9

36

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.

stevehipwell
  • 56,138
  • 6
  • 44
  • 61
  • 8
    +1 The other answers had at least one bug each, that's why it's not worth using RE for these tasks. – soulmerge Sep 04 '09 at 08:31
  • 3
    Two bugs even :( but yes, I fundamentally agree. – Joey Sep 04 '09 at 08:33
  • 1
    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 Sep 04 '09 at 08:35
  • 3
    Well, in that case capture each individual part of the coordinate in a capture group and validate them afterwards. – Joey Sep 04 '09 at 08:47
  • 1
    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 Sep 04 '09 at 08:48
31

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
  • 344,408
  • 85
  • 689
  • 683
  • 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 Sep 04 '09 at 08:33
18

The recently released rgxg command line tool generates regular expressions that match a specific number range:

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

For more information, see https://rgxg.github.io.

hvhaugwitz
  • 181
  • 1
  • 3
3

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)$
We Are All Monica
  • 13,000
  • 8
  • 46
  • 72
  • 1
    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 Sep 04 '09 at 11:42
2

Try this:

^(0|[1-9][0-9]?|1[0-7][0-9]|180)$
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • @Ionut G. Stan: I think that’s just the alternative if matching just numbers with no leading zeros is too difficult. – Gumbo Sep 04 '09 at 08:38
1

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
  • 71
  • 2
  • You forgot single digit 1 to 9. – Robert L Sep 14 '09 at 11:19
  • 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 Sep 15 '09 at 14:29
0

I modified Gumbo's:

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

Try that.

shA.t
  • 16,580
  • 5
  • 54
  • 111
Robert L
  • 1,963
  • 2
  • 13
  • 11
0

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
  • 50,398
  • 25
  • 166
  • 151
0

You can use the below regular expression

^([0-1]?[0-7]?[0-9])|180$
Praveen
  • 55,303
  • 33
  • 133
  • 164
Amjad Sham
  • 21
  • 3