Числа между 99 и 9999999 регулярным выражением - PullRequest
0 голосов
/ 10 января 2019

Я пытаюсь сгенерировать регулярное выражение, которое будет соответствовать любым числам в диапазоне от 99 до 9999999. У меня проблемы с пониманием того, как генерация диапазонов чисел обычно работает. Мне удалось найти в сети генератор диапазонов, который выполняет эту работу за меня, но я хочу понять, как он на самом деле работает.

Моя попытка сделать этот диапазон выглядит следующим образом:

(99|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

Предполагается, что он соответствует 99, любому 3-значному или 4-значному номеру, но не работает должным образом. При тестировании он соответствует только номерам 99 и 3-значным числам. Четырехзначные числа не совпадают вообще. Если я пишу только часть для 4-значных чисел как

[1-9][0-9][0-9][0-9]

Он соответствует 4-значным числам, но когда я его строю, как в первом примере, он не работает. Может кто-нибудь дать мне некоторое разъяснение, как это на самом деле работает и как успешно сгенерировать регулярное выражение для диапазона от 99 до 9999999.

Ссылка на демо - Здесь

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Итак, вы хотите знать, как это работает ...

Регулярные выражения не имеют реального понимания значений чисел в вашей строке, их интересует только то, как они представлены, поэтому поиск чисел в диапазоне кажется более неловким, чем должно быть. Единственная причина, по которой ваш движок регулярных выражений может понимать диапазон в классе символов , например [0-9], заключается в том, что позиции символов в списке (диапазон символов, например [&-~]) столь же действителен и одинаково понятен для него.)

Итак, чтобы соответствовать диапазону, например, 99-9999999, вам нужно разобрать, как это выглядит: буквальное «99», или три цифры без начального нуля, или четыре цифры без начального нуля и т. Д.

Но это то, что сделал демо , верно? И это не сработало. Из вашей тестовой строки "9293" ваше регулярное выражение соответствует только 929. Здесь произошло то, что движок регулярных выражений жаждет вернуть полное совпадение - как только он найдет одно, он вернет его, даже если позднее было возможно лучшее / более длинное совпадение.


Вот как произошло это совпадение. (Я пропущу некоторые детали, такие как группировка , так как они здесь не очень важны.)

Шаг 1.

Движок сравнивает первый токен в регулярном выражении с первым символом в строке

(<strong><em><kbd>9</kbd></em></strong>9|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

<kbd><strong><em>9</em></strong></kbd>293

Успех, они совпадают.

Шаг 2.

Затем движок продвигается к следующему токену в регулярном выражении и следующему символу в строке и сравнивает их.

(<strong><em>9</em></strong><kbd>9</kbd>|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

<strong><em>9</em></strong><kbd>2</kbd>93

Ошибка, нет совпадения. Двигатель остановится и вернет ошибку здесь, но вы используете чередование через |, поэтому он знает, что есть альтернативное выражение для попытки.

Шаг 3.

Движок переходит к первому токену следующего альтернативного выражения в регулярном выражении и перематывает позицию в строке.

(99|<strong><em><kbd>[1-9]</kbd></em></strong>[0-9][0-9]|[1-9][0-9][0-9][0-9])

<strong><em><kbd>9</kbd></em></strong>293

Успех, они совпадают.

Шаг 4.

Продолжение.

(99|<strong><em>[1-9]<kbd>[0-9]</kbd></em></strong>[0-9]|[1-9][0-9][0-9][0-9])

<strong><em>9<kbd>2</kbd></em></strong>93

Match.

Шаг 5.

И снова.

(99|<strong><em>[1-9][0-9]<kbd>[0-9]</kbd></em></strong>|[1-9][0-9][0-9][0-9])

<strong><em>92<kbd>9</kbd></em></strong>3

Успех. Полное выражение соответствует. Нет необходимости пробовать оставшуюся альтернативу. Возвращенное совпадение:

<strong><em>929</em></strong>

Как вы, наверное, поняли, если бы ваша входная строка была вместо "9923", то шаг 2 соответствовал бы и двигатель там остановился бы и возвратил "99" .

Как вы, вероятно, уже поняли, если вы переставите свои альтернативные выражения с самого длинного на самое короткое

([1-9][0-9][0-9][0-9]|[1-9][0-9][0-9]|99)

сначала будет предпринята самая длинная попытка, которая будет соответствовать и вернуть ожидаемое "9293" .


Упрощен

Это все еще довольно многословно, тем более, что вы увеличиваете количество цифр в вашем диапазоне. Есть несколько вещей, которые вы можете сделать, чтобы упростить его.

Класс символов [0-9] может быть представлен классом символов \d.

([1-9]\d\d\d|[1-9]\d\d|99)

И вместо того, чтобы повторять их, используйте квантификатор в фигурных скобках, например:

([1-9]\d{3}|[1-9]\d{2}|99)

Как это бывает, квантификаторы также могут принимать форму {min, max}, поэтому вы можете объединить два аналогичных альтернативных варианта:

([1-9]\d{2,3}|99)

Вы могли бы ожидать, что это вернет вас назад, возвращая «929» снова, двигатель жадный и все такое, но квантификаторы по умолчанию жадные , поэтому они попытаются собрать как можно больше. Это хорошо подходит для большего желаемого диапазона:

([1-9]\d{2,6}|99)

Завершение

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

Скорее всего, вас съедят на 1000 гр.

Если уВы пытаетесь выяснить, сколько грёсов собирается съесть вас, вы можете использовать

[1-9]\d{2,6}|99

, который будет возвращать 1000 .

Однако эта Сорта возвращается к исходной проблеме с вашей демонстрацией. Если это значение «12345678 grue», которое находится за пределами диапазона, это будет соответствовать «1234567», что может быть не тем, что вы хотите. Вы можете убедиться, что за выбранным вами номером не сразу следует (или не предшествует) другая цифра, используя отрицательные выражения .

(?<!\d)([1-9]\d{2,6}|99)(?!\d)

(?<!\d) означает «с этой позиции, предыдущий символ не является цифрой», а (?!\d) означает «с этой позиции, следующий символ не является цифрой».

Круглые скобки вокруг альтернатив возвращаются, так как они необходимы здесь для группировки, в противном случае lookbehind будет только частью и применяется в первом альтернативном выражении, а lookahead будет только частью и применяется во втором альтернативе.

С другой стороны, если вы пытаетесь убедиться, что вся строка only состоит из числа в вашем диапазоне, вы хотите вместо этого использовать якоря ^ и $ (начало строки и конец строки соответственно):

^([1-9]\d{2,6}|99)$

И, наконец, вы можете обменять группу захвата на группу без захвата (?:...), поэтому:

^(?:[1-9]\d{2,6}|99)$

или

(?<!\d)(?:[1-9]\d{2,6}|99)(?!\d)

Вы по-прежнему будете захватывать число во время матча, оно просто не будет повторяться при групповом захвате. (Lookarounds уже не захватывает, не нужно беспокоиться о них.)

0 голосов
/ 10 января 2019

Прежде всего вам нужны некоторые строковые границы для регулярных выражений (все, кроме цифры, в моем примере я использую ^ и $ - начало и конец строки или строки)

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

^([1-9][0-9]{2,6}|99)$
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...