Регулярное выражение для соответствия 3 числам

В настоящее время я пытаюсь создать регулярное выражение, которое может соответствовать 3 числам при определенных обстоятельствах. Сейчас я пробовал разные попытки, но это не сработает с одним выражением - это либо "ложное срабатывание", либо "соответствие неправильным числам"...

Прописью: я хочу сопоставить ЛЮБЫЕ 3 цифры, которые

  • Появляется в начале строки
  • Появление где-то внутри строки
  • (Конец строки НЕ возможен)

IF:

  • Не существует другой трехзначной группы, соответствующей этому условию. (неоднозначно)
  • За группой не следует буква «p» или «i».
  • Группу не возглавляет "x"

В примерах (число в () — это то, что я хочу сопоставить):

  • Это (321) пример.
  • (321) также
  • включая (321) // в принципе невозможно, но не помешает.
  • у этого (321) есть еще одна группа с p: 122p
  • у этого (321) есть еще одна группа с I: 123i
  • этот x235 следует игнорировать, потому что (123) - это то, что я хочу сопоставить.
  • (123) это то, что я хочу, а не x111 или 125p или 999i
  • в этом 111 случае нет решения 555

(Мне нужно это как (1 число) (2 числа) - но это будет просто небольшая модификация совпадения из 3 чисел)

Моя последняя попытка выглядела так:

(?:[^x]|^)(\d{1})(\d{2})[^pi]

Визуализация регулярных выражений

Демонстрация отладки

Однако в последнем случае это не удается. Я попытался скрыть это с помощью preg_match_all(...) === 1, чтобы убедиться, что совпал только один результат.

Однако теперь тестовая строка типа «101 202» будет положительной, потому что первая проверка соответствует 101 (включая пробелы), а затем не соответствует 202, из-за чего шаблон предполагает, что 101 является единственным допустимым решением, что неверно.

(?:[^x]|^)(\d{1})(\d{2})[^pi]

Визуализация регулярных выражений

Демонстрация отладки

Есть идеи?

Примечание. Он должен работать с разными механизмами регулярных выражений, независимо от того, php, javascript, java, .net или Ook! :)


person dognose    schedule 25.04.2014    source источник
comment
Я думаю, вы все усложняете, и вы просто хотите использовать некоторые обходные пути. Попробуйте этот шаблон ~(?<!x)\d{3}(?![pi]|$)~i и скажите, что не так с совпадениями, которые он получает.   -  person HamZa    schedule 26.04.2014
comment
@HamZa тоже подумал о том, чтобы осмотреться. Мой подход был (?<!x)(?:(?:(\d{1})(\d{2}))(?![pi])). Однако в Debuggex поиск назад завершается с ошибкой компиляции, а другие тестеры Regex также не возвращают никаких совпадений, поэтому я хотел бы использовать более надежное решение, чем просмотр назад: debuggex.com/r/jUytMQhBFWo93f_V   -  person dognose    schedule 26.04.2014
comment
Вы получаете сообщение об ошибке, потому что JavaScript не поддерживает просмотр назад. Каждый современный движок регулярных выражений (java, .net, python, pcre и многие другие) поддерживает поиск. Это мощный инструмент. Так почему бы вам не использовать его, если вы используете php?   -  person HamZa    schedule 26.04.2014
comment
@HamZa Проблема в том, что я не хочу предоставлять клиенту шаблон для проверки. Я не знаю, использует ли клиент Javascript, php, .net или что-то еще. Заявление о том, что Javascript не поддерживается, было бы последним подходом :)   -  person dognose    schedule 26.04.2014
comment
Ну, это ваша проблема. Есть несколько хакерских способов эмулировать lookbehind, но все зависит от языка. В JavaScript вы можете использовать обратный вызов. Поэтому заявлять, что я хочу универсальное регулярное выражение в этом случае, безумно, поскольку синтаксис регулярных выражений не является универсальным, не говоря уже об их возможностях. Просто посмотрите на это, например   -  person HamZa    schedule 26.04.2014
comment
@HamZa вот почему я ищу базовый шаблон, который может понять каждый движок регулярных выражений ... Я не ожидаю, что это возможно - но никогда не знаешь всего - вот почему я подумал: давайте ТАК шанс :р   -  person dognose    schedule 26.04.2014
comment
@HamZa Моя пометка для php вводила в заблуждение (просто используя PHP в качестве тестовой системы) - извините за это.   -  person dognose    schedule 26.04.2014


Ответы (2)


Мы можем записать числа, которые вы ищете, следующим образом:

re_n = (?:[^x]|^)\d\d\d(?:[^ip]|$)

Тогда все выражение:

^(?!.*re_n.*re_n.*$).*(re_n)

который в основном устраняет двойные числа, используя отрицательный просмотр вперед после якоря начала строки, а затем сопоставляет действительное число.

Интерполированное выражение выглядит некрасиво:

/^(?!.*(?:(?:[^x]|^)\d\d\d(?:[^ip]|$)).*(?:(?:[^x]|^)\d\d\d(?:[^ip]|$)).*$).*((?:(?:[^x]|^)\d\d\d(?:[^ip]|$)))/

Этот код Perl:

my $re_n = qr/(?:[^x]|^)\d\d\d(?:[^ip]|$)/;
while (<DATA>) { chomp;
    if (/^(?!.*$re_n.*$re_n.*$).*($re_n)/) {
        print "$_: $1\n";
    } else {
        print "$_: NONE\n";
    }   
}

__DATA__
This is 321 an example.
321 also
including 321 //basically not possible, but can't hurt.
this 321 has another group with a p: 122p
this 321 has another group with a I: 123i
this x235 should be ignored cause 123 is what i want to match.
123 is what i want, not x111 or 125p or 999i
in this 111 case there is no solution 555

Производит:

This is 321 an example.:  321 
321 also: 321 
including 321 //basically not possible, but can't hurt.:  321 
this 321 has another group with a p: 122p:  321 
this 321 has another group with a I: 123i:  321 
this x235 should be ignored cause 123 is what i want to match.:  123 
123 is what i want, not x111 or 125p or 999i: 123 
in this 111 case there is no solution 555: NONE
person perreal    schedule 26.04.2014
comment
Это ужасно, вы правы, но, похоже, это хорошо работает в разных реализациях Regex. И хорошая идея со всем выражением. - person dognose; 26.04.2014

Я не уверен, что это то, что вы хотите, попробуйте:

JAVASCRIPT

var myregexp = /(?:\b[\s]?|[^x])([\d]{1}[\d]{2})(?:[^pi]|[\s]?\b)/m;

http://regex101.com/r/jY6mG9

PHP

preg_match_all('/(?:\b[\s]?|[^x])([\d]{1}[\d]{2})(?:[^pi]|[\s]?\b)/m', $code, $result, PREG_PATTERN_ORDER);

http://regex101.com/r/oW1tJ7

JAVA

Pattern regex = Pattern.compile("(?:\\b[\\s]?|[^x])([\\d]{1}[\\d]{2})(?:[^pi]|[\\s]?\\b)", Pattern.MULTILINE);

РУБИ

regexp = /(?:\b[\s]?|[^x])([\d]{1}[\d]{2})(?:[^pi]|[\s]?\b)/

http://rubular.com/r/OHgMLS2gGs

ПИТОН

reobj = re.compile(r"(?:\b[\s]?|[^x])([\d]{1}[\d]{2})(?:[^pi]|[\s]?\b)", re.MULTILINE)

https://pythex.org< /а>

C (PCRE)

myregexp = pcre_compile("(?:\\b[\\s]?|[^x])([\\d]{1}[\\d]{2})(?:[^pi]|[\\s]?\\b)", PCRE_MULTILINE, &error, &erroroffset, NULL);
person Pedro Lobito    schedule 26.04.2014
comment
Что нет PCRE, я шучу... Хороший ответ Я никогда не думал предоставлять почти все возможные варианты языков. Я собираюсь начать делать это для regex вопросов. - person MattSizzle; 26.04.2014
comment
@MattGreen PCRE тоже :) - person Pedro Lobito; 26.04.2014
comment
хотя я не уверен, что этого хочет ОП. - person Pedro Lobito; 26.04.2014
comment
@Tuga: +1 за работу, которую вы там проделали :) Но это не совсем то, что мне нужно: я создаю API, где пользователь может публиковать данные программно. Чтобы упростить задачу, я не хочу предоставлять пользователю регулярное выражение вместе с определением поля, чтобы проверить его данные перед публикацией для каждого поля. Когда клиент извлекает эту информацию, я не знаю, является ли это клиентом php или javascript. Предоставление ВСЕХ регулярных выражений ВСЕ время кажется неподходящим. - person dognose; 26.04.2014
comment
@Tuga: только что увидел, что это действительно все время один и тот же шаблон (просто смотрел по-разному из-за разных побегов). Просто ложное срабатывание в случае двойного числа не разрешается этим :) - person dognose; 26.04.2014
comment
@dognose Рад помочь вам :) - person Pedro Lobito; 26.04.2014