7

I have a field on a form that takes the following values: -1, 2-10, 99

I have a business rule that's concerned with answers 2-10.

I'm trying to write a regular expression that will match 2-10 but not 99, and I'm having trouble.

The original expression:

^2|3|4|5|6|7|8|9|10$

Fails because 99 is matched (technically, twice). Also, the Line boundries are something I've never been comfortable with. I oberve different behavior from them in expresso than I do in other places (e.g. .net). In this particular instance, the regex is being run in javascript. Anyway, expresso seems to ignore them (and if I put the values in brackets:

^[2|3|4|5|6|7|8|9|10]$

^[2-9]$

either "all spelled out" or as a range, expresso never returns any matches if I specify the opening line/string closing line/string characters (and yes, I was trying to match the 10 separately in the second case there).

I know, I know. If you use a regex to solve a problem, then you have two problems (and presumably they'll start inviting friends over, thing 1 and thing 2 style). I don't have to use one here; I may switch to a case statement. But it seems like I should be able to use a regex here, and it seems a reasonable thing to do. I'm still pretty green when it comes to the regex;

Georg Schölly
  • 124,188
  • 49
  • 220
  • 267
peacedog
  • 1,415
  • 20
  • 32

6 Answers6

46

This is clearly a case where you shouldn't use RegExp but numerical evaluation:

var num = parseInt(aNumber, 10);
if (num >= 2 && num <= 10) {
    alert("Match found!");
}
Georg Schölly
  • 124,188
  • 49
  • 220
  • 267
  • 3
    parseInt(aNumber,10) // Don't forget the radix or you can be surprised. – some Feb 09 '09 at 16:48
  • well played, sir. Well played. – Learning Feb 09 '09 at 16:52
  • While i do agree this would be a far superior solution to regexes in most cases, an even better solution would be to constrain the input by means of UI (dropdownlist anyone?). However, the question is specifically about a regualar expression. – Kris Feb 09 '09 at 17:19
  • 3
    Just because the question is about a regular expression doesn't mean the right answer is a well-formed regex. http://weblogs.asp.net/alex_papadimoulis/archive/2005/05/25/408925.aspx – Randy Feb 09 '09 at 17:28
  • The problem with constraining is that the input-ui has also to accept -1 and 99, therefore this wouldn't work. It's about extracting data later. – Georg Schölly Feb 09 '09 at 17:42
  • the second argument to parseInt() isn't really necessary, there are no zeros in the field except the one in the number 10. Yet it's still better to be on the safe side. – Georg Schölly Feb 09 '09 at 17:55
  • 1
    @ Kris - dropdowns don't stop people from submitting any value to the server. @ gs - actually, since this is user input that's being parsed, I would consider the radix to be required here. You can never know what they'll enter. – Peter Bailey Feb 09 '09 at 18:56
  • @BaileyP, I never said don't do server side validation! – Kris Feb 09 '09 at 19:21
  • That's not unreasonable though I was really more curious about making the regex work, and I should have been clearer on that. Also, no, drop down is not an option. – peacedog Feb 10 '09 at 11:59
  • My solution has nothing to do with drop downs, it's about choosing the right technic. – Georg Schölly Feb 10 '09 at 12:02
20

You need parantheses for that. I would further use ranges to keep things readable:

^([2-9]|10)$
Svante
  • 50,694
  • 11
  • 78
  • 122
soulmerge
  • 73,842
  • 19
  • 118
  • 155
  • "^" and "$" should both be replaced by "\b". The meaning would be the same, but you can then globally apply it to a complete string. – Tomalak Feb 09 '09 at 17:21
7

Use parentheses around the alternations, since concatenation has higher precedence than alternation:

^(2|3|4|5|6|7|8|9|10)$
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
1

A complete javascript function to match either 2 though 9, or 10

<script type="text/javascript">
    function validateValue( theValue )
    {
        if( theValue.match( /^([2-9]{1}|10)$/ ) )
        {
            window.alert( 'Valid' );
        }
        else
        {
            window.alert( 'invalid' );
        }
        return false;
    }
</script>

The regex is easily expanded to incorporate all of your rules:

/^(-1|[2-9]|10|99)$/ // will match -1, 2-10, 99

edit: I forgot to mention you'll have to substitute your own true/false situational logic. edit2: added missing parenthesis to 2nd regex.

Kris
  • 40,604
  • 9
  • 72
  • 101
  • Wrong. /^-1|[2-9]|10|99$/ will match -1 at the beginning of the string, or a 2,3,4,5,6,7,8,9 anywhere, or a 10 anywhere, or 99 at the end of the string. Perhaps you meant: /^(-1|[2-9]|10|99)$/ (and your first regexp is wrong too) – some Feb 09 '09 at 17:52
  • I just found out my testcases were not extensive enough and that makes you correct on both counts. I have adapted the snippet. – Kris Feb 10 '09 at 13:37
0

This online utility is very good at generating re's for numeric ranges: http://utilitymill.com/utility/Regex_For_Range. For the range 2-10 inclusive, it gives this expression: \b0*([2-9]|10)\b. If you want to omit leading 0's, take out the "0*" part.

PaulMcG
  • 62,419
  • 16
  • 94
  • 130
0

The reason your original expression fails is because you're matching ^2, 3, 4, 5, 6, 7, 8, 9, 10$.

Try this regex: ^(2|3|4|5|6|7|8|9|10)$

Glen Solsberry
  • 11,960
  • 15
  • 69
  • 94