Жадное совпадение с регулярным выражением не работает должным образом - PullRequest
4 голосов
/ 12 сентября 2009

У меня есть очень простое регулярное выражение, которое я просто не могу понять, почему оно не работает, поэтому вопрос состоит из двух частей. Почему моя текущая версия не работает и каково правильное выражение.

Правила довольно просты:

  1. Должно содержать не менее 3 символов.
  2. Если символ% является первым символом, он должен содержать не менее 4 символов.

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

  • AB - ошибка
  • ABC - пропуск
  • ABCDEFG - пропуск
  • % - сбой
  • % AB - сбой
  • % ABC - пропуск
  • % ABCDEFG - пропуск
  • %% AB - пропуск

Выражение, которое я использую:

^%?\S{3}

Что для меня значит:

  • ^ - начало строки
  • %? - Жадная проверка на 0 или 1% символа
  • \S{3} - 3 других символа, которые не являются пробелами

Проблема в том, что %? по какой-то причине не выполняет жадную проверку. Он не ест символ%, если он существует, поэтому дело «% AB» проходит, что, я думаю, должно быть неудачным. Почему %? не ест символ%?

Кто-нибудь, пожалуйста, покажите мне свет:)

Редактировать: Ответ, который я использовал, был ниже: ^(%\S{3}|[^%\s]\S{2}) Хотя это был ответ из двух частей, и Алан действительно заставил меня понять, почему. Я не использовал его версию ^(?>%?)\S{3}, потому что она работала, но не в реализации javascript. И отличные ответы, и много помощи.

Ответы [ 4 ]

9 голосов
/ 12 сентября 2009

Regex всегда будет пытаться сопоставить весь шаблон, если может - «жадный» не означает «всегда захватывает символ, если он существует», но вместо этого означает «всегда захватывает символ, если он существует и состязание может быть сделано с этим схваченным".

Вместо этого вы, вероятно, хотите что-то вроде этого:

^(%\S{3}|[^%\s]\S{2})

Что будет совпадать либо с%, за которым следуют 3 символа, либо с не%, без пробела, за которым следуют еще 2.

8 голосов
/ 12 сентября 2009

Слово для поведения, которое вы описали, не жадный , это притяжательное . Обычные, жадные квантификаторы совпадают настолько, насколько они могут изначально, но отступают, если необходимо, чтобы все регулярные выражения совпадали (мне нравится думать о них как о жадных, но вмещающих ). Вот что с вами происходит: %? изначально соответствует лидирующему знаку процента, но если для общего совпадения осталось недостаточно символов, он отбрасывает знак процента и позволяет \S{3} сопоставить его.

Некоторые разновидности регулярных выражений (включая Java и PHP) поддерживают собственнические квантификаторы , которые никогда не отступают, даже если это приводит к сбою общего соответствия. В .NET их нет, но есть следующая лучшая вещь: атомные группы . Все, что вы помещаете в атомарную группу, действует как отдельное регулярное выражение - оно либо совпадает с той позицией, в которой оно применено, либо нет, но оно никогда не возвращается назад и пытается сопоставить больше или меньше, чем изначально, просто потому, что остальные регулярное выражение терпит неудачу (то есть механизм регулярных выражений никогда не возвращает в атомную группу). Вот как бы вы использовали это для вашей проблемы:

^(?>%?)\S{3}

Если строка начинается со знака процента, ей соответствует (?>%?), и если для соответствия \S{3} недостаточно символов, регулярное выражение завершается неудачей.

Обратите внимание, что атомные группы (или притяжательные кванторы) не нужны для решения этой проблемы, как продемонстрировал @Dav. Но это очень мощные инструменты, которые могут легко сделать разницу между невозможным и возможным , или слишком чертовски медленным и гладким, как может быть .

1 голос
/ 12 сентября 2009

Я всегда люблю смотреть на вопросы RE, чтобы узнать, сколько времени люди тратят на них, чтобы "сэкономить время"

str.len() >= str[0]=='&' ? 4 : 3

Хотя в реальной жизни я бы сказал более откровенно, я просто написал это так, потому что по какой-то причине некоторые люди считают краткость кода преимуществом (я бы назвал это анти-преимуществом, но сейчас это не популярно). )

0 голосов
/ 12 сентября 2009

Попробуйте регулярное выражение, немного измененное на основе оригинального Дэва:

^(%\S{3,}|[^%\s]\S{2,})

с включенным параметром регулярного выражения "^ и $ match при переносе строки".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...