7

I am looking for a regular expression that will match any number from 1 to 50 inclusive. So far, I have found examples but they all allow the string to contain a decimal point, which I do not want to include. So 1,13,24,50 are OK but 1. ,etc are not. Is there a REGEXP that I can use?

Thanks in advance, Tim

Phrogz
  • 296,393
  • 112
  • 651
  • 745
Tim
  • 71
  • 1
  • 1
  • 3

5 Answers5

13

Try this:

/^(?:[1-9]|[1-4][0-9]|50)$/

UPDATE:

Now that I see the question has been updated to refer to MySQL, this changes things significantly. The above-mentioned regular expression uses non-capturing parens which are not supported by MySQL. But it also begs the question; should you really be using regular expressions to solve this problem? We really have to look at how you are storing your numbers that must be between 1 and 50. Are they varchars? Are they ints? I'll demonstrate how to solve it both ways. First I'll set up a test table with indexes:

create table regextest (
    id int unsigned primary key auto_increment,
    varchar_number varchar(5) not null,
    int_number int not null,
    index(varchar_number),
    index(int_number)
) engine=innodb;

Now put some test data into it making sure all our edge cases are covered:

insert into regextest (varchar_number, int_number)
    values ('0', 0), ('1', 1), ('35', 35), ('49', 49), ('50', 50), ('51', 51);

And now, here is a query that will solve your problem assuming that your numbers are stored as strings in the varchar_number column:

mysql> select * from regextest where varchar_number rlike '^([1-9]|[1-4][0-9]|50)$';
+----+----------------+------------+
| id | varchar_number | int_number |
+----+----------------+------------+
|  2 | 1              |          1 |
|  3 | 35             |         35 |
|  4 | 49             |         49 |
|  5 | 50             |         50 |
+----+----------------+------------+
4 rows in set (0.00 sec)

This works but it will perform poorly on large data sets because it can't use an index even if one is present. MySQL must run the regular expression once for every row in the table. Suppose your numbers between 1 and 50 were stored as ints in the int_number column. You could simply do this:

mysql> select * from regextest where int_number between 1 and 50;
+----+----------------+------------+
| id | varchar_number | int_number |
+----+----------------+------------+
|  2 | 1              |          1 |
|  3 | 35             |         35 |
|  4 | 49             |         49 |
|  5 | 50             |         50 |
+----+----------------+------------+
4 rows in set (0.00 sec)

This query will perform well because it can use an index and it's also more readable and more maintainable. Wins all around.

Asaph
  • 159,146
  • 25
  • 197
  • 199
  • Hi, thanks for your comment. I am trying the following in MySQL: Select 1 REGEXP '/^(?:[1-9]|[1-4][0-9]|50)$/' but it comes up with the error: Got error 'repetition-operator operand invalid' from regexp. I have seen that this might be due to not escaping a backslash, and I have tried doing // instead of / but still did not work...Any ideas? – Tim Dec 03 '10 at 08:50
  • @Tim: The problem is probably the `(?:...)` syntax, which introduces a non-capturing group. It sounds like MySQL doesn't support that, and is trying to treat `?` as a repetition operator, though of course it has nothing to repeat. If you replace the `(?:...)` with ordinary parentheses `(...)`, it should work. – Antal Spector-Zabusky Dec 03 '10 at 10:53
  • Thanks, I tried but /^(([1-9]|[1-4][0-9]|50)$/) but it does not match the correct digits. – Tim Dec 03 '10 at 11:36
  • @Tim: I've updated my answer with MySQL specific information to help you work through this. – Asaph Dec 03 '10 at 15:03
  • I wonder if Tim is trying to select a single column with this value, or find integers in the middle of large strings that or within this range. – Phrogz Dec 03 '10 at 15:59
  • Hi, thanks for your comments. I used the method suggested by Asaph and it works. I have a varchar column, and I am using a where statement (in conjunction with other search criteria/columns), and the final criterion is that this varchar column must be a number between 1 and 50. MySQL uses the left prefix of an index and only examines a small (max < 400 but usually around 80) amount of rows using RLIKE...Thanks! – Tim Dec 03 '10 at 18:04
4
'^(0?\d|[1-4]\d|50)$'

That is:

  • The start of the input
  • followed by a single digit (optional preceded by a 0), or
  • followed by a 1-4 followed by any digit, or
  • followed by 50
  • and then ensure that we see the end of the input.

Edit: The above allows 0 (and 00) which you surely don't want. So, assuming you didn't really want leading zeros allowed anyhow:

'^([1-9]|[1-4]\d|50)$'

Edit: As the OP's later comments indicate that this is for MySQL, I've changed the syntax for specifying the pattern.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 2
    This will match `0` which is not allowed. – Asaph Dec 03 '10 at 06:28
  • @Tim You should have specified MySQL in your original question. The slashes in some of our examples are regular expression literal delimiters in some languages, but not MySQL. I've updated my answer to match [MySQL Regexp Syntax](http://dev.mysql.com/doc/refman/5.1/en/regexp.html). – Phrogz Dec 03 '10 at 14:27
2

^([1-9]|[1-4][0-9]|50)$

Jon Abaca
  • 821
  • 1
  • 9
  • 14
  • Thanks. However this allows for example 1. – Tim Dec 03 '10 at 11:33
  • @Tim If your above comment means "it allows `1.`", then you are wrong: it does not allow a period. If your comment means "it allows `1`", then this is what you explicitly stated it should match. The above pattern looks fine to me. – Phrogz Dec 03 '10 at 14:31
0

"Cheating" with Perl6::Rules:

/ ( \d+ ) { 1 <= $1 && $1 <= 50 or fail } /

Or in Perl 5.10 and up,

/(\d+)(?(?{1>$1||50<$1})(*FAIL))/
ephemient
  • 198,619
  • 38
  • 280
  • 391
0

try this one

([0-4]{1}[0-9]{0,1}[.]{0,1}[0-9]{0,2}|50)

will Do Following

45.00 - Match
4     - Match
78    - Not Match
51    - Not Match
21.25 - Match
HMP
  • 31
  • 2
  • Three problems: (1) The OP said he *didn't* want to match decimal points. (2) He also said the number can't be `0` or `00`: your regex matches both. (3) Your quantifiers need work; `{0,2}` is okay, but `{0,1}` should be written as `?`, and `{1}` should be deleted. All it does is tell the regex engine to do what it was going to do anyway: match exactly one of the atom it's attached to. – Alan Moore Dec 03 '10 at 08:51