Регулярное выражение для 1-50 без десятичной точки

Я ищу регулярное выражение, которое будет соответствовать любому числу от 1 до 50 включительно. До сих пор я нашел примеры, но все они позволяют строке содержать десятичную точку, которую я не хочу включать. Таким образом, 1,13,24,50 в порядке, а 1. и т. д. - нет. Есть ли REGEXP, который я могу использовать?

Заранее спасибо, Тим


person Tim    schedule 03.12.2010    source источник


Ответы (5)


Попробуй это:

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

ОБНОВИТЬ:

Теперь, когда я вижу, что вопрос был обновлен, чтобы относиться к MySQL, это значительно меняет ситуацию. Вышеупомянутое регулярное выражение использует незахватывающие скобки, которые не поддерживаются MySQL. Но также возникает вопрос; вы действительно должны использовать регулярные выражения для решения этой проблемы? Нам действительно нужно посмотреть, как вы храните свои числа, которые должны быть от 1 до 50. Они varchar? Они int? Я покажу, как решить это в обоих направлениях. Сначала я настрою тестовую таблицу с индексами:

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;

Теперь поместите в него несколько тестовых данных, чтобы убедиться, что все наши пограничные случаи покрыты:

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

А теперь вот запрос, который решит вашу проблему, предполагая, что ваши числа хранятся в виде строк в столбце varchar_number:

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)

Это работает, но плохо работает с большими наборами данных, поскольку не может использовать индекс, даже если он присутствует. MySQL должен запускать регулярное выражение один раз для каждой строки в таблице. Предположим, ваши числа от 1 до 50 были сохранены как ints в столбце int_number. Вы можете просто сделать это:

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)

Этот запрос будет работать хорошо, потому что он может использовать индекс, а также более удобен для чтения и обслуживания. Побеждает во всем.

person Asaph    schedule 03.12.2010
comment
Привет, спасибо за ваш комментарий. Я пытаюсь сделать следующее в MySQL: выберите 1 REGEXP '/^(?:[1-9]|[1-4][0-9]|50)$/', но появляется ошибка: Got error ' недопустимый операнд оператора повторения 'из регулярного выражения. Я видел, что это может быть связано с отсутствием экранирования обратной косой черты, и я попытался сделать // вместо /, но все равно не сработало... Есть идеи? - person Tim; 03.12.2010
comment
@Tim: проблема, вероятно, заключается в синтаксисе (?:...), который вводит группу без захвата. Похоже, что MySQL не поддерживает это и пытается рассматривать ? как оператор повторения, хотя, конечно, ему нечего повторять. Если вы замените (?:...) обычными круглыми скобками (...), это должно сработать. - person Antal Spector-Zabusky; 03.12.2010
comment
Спасибо, я пытался, но /^(([1-9]|[1-4][0-9]|50)$/) не соответствует правильным цифрам. - person Tim; 03.12.2010
comment
@Tim: я обновил свой ответ, указав конкретную информацию о MySQL, чтобы помочь вам справиться с этим. - person Asaph; 03.12.2010
comment
Интересно, пытается ли Тим выбрать один столбец с этим значением или найти целые числа в середине больших строк, которые или находятся в этом диапазоне. - person Phrogz; 03.12.2010
comment
Привет, спасибо за ваши комментарии. Я использовал метод, предложенный Асафом, и он работает. У меня есть столбец varchar, и я использую оператор where (в сочетании с другими критериями/столбцами поиска), и последним критерием является то, что этот столбец varchar должен быть числом от 1 до 50. MySQL использует левый префикс индекса и проверяет только небольшое (максимум ‹ 400, но обычно около 80) количество строк, используя RLIKE... Спасибо! - person Tim; 03.12.2010

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

То есть:

  • Начало ввода
  • за которой следует одна цифра (необязательно с предшествующим 0), или
  • за которым следует цифра 1-4, за которой следует любая цифра, или
  • затем 50
  • а затем убедитесь, что мы видим конец ввода.

Редактировать. Приведенное выше позволяет использовать 0 (и 00), что вам наверняка не нужно. Итак, предполагая, что вы действительно не хотите, чтобы начальные нули разрешались в любом случае:

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

Редактировать: Поскольку более поздние комментарии OP указывают, что это для MySQL, я изменил синтаксис для указания шаблона.

person Phrogz    schedule 03.12.2010
comment
Это будет соответствовать 0, что недопустимо. - person Asaph; 03.12.2010
comment
@Tim Вы должны были указать MySQL в своем первоначальном вопросе. Косые черты в некоторых наших примерах являются литеральными разделителями регулярных выражений в некоторых языках, но не в MySQL. Я обновил свой ответ, чтобы он соответствовал синтаксису MySQL Regexp. - person Phrogz; 03.12.2010

Попробуй это

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

будет делать следующее

45.00 - Match
4     - Match
78    - Not Match
51    - Not Match
21.25 - Match
person HMP    schedule 03.12.2010
comment
Три проблемы: (1) ОП сказал, что он не хочет сопоставлять десятичные точки. (2) Он также сказал, что число не может быть 0 или 00: ваше регулярное выражение соответствует обоим. (3) Ваши квантификаторы нуждаются в доработке; {0,2} можно, но {0,1} следует записать как ?, а {1} следует удалить. Все, что он делает, это говорит механизму регулярных выражений сделать то, что он собирался сделать в любом случае: сопоставить ровно один из атомов, к которым он присоединен. - person Alan Moore; 03.12.2010

«Обман» с помощью Perl6::Rules:

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

Или в Perl 5.10 и выше,

/(\d+)(?(?{1>$1||50<$1})(*FAIL))/
person ephemient    schedule 03.12.2010
comment
Или в Perl5: /^ ( \d+ ) $ (?(?{ 1 > $1 || 50 < $1 }) (*FAIL) )/x - person tchrist; 03.12.2010

person    schedule
comment
Спасибо. Однако это позволяет, например, 1. - person Tim; 03.12.2010
comment
@Tim Если ваш комментарий выше означает, что он разрешает 1., то вы ошибаетесь: он не разрешает точку. Если ваш комментарий означает, что он разрешает 1, то это то, что вы явно указали, что он должен соответствовать. Приведенный выше шаблон выглядит хорошо для меня. - person Phrogz; 03.12.2010