Регулярные выражения POSIX ограничивают повторения - PullRequest
1 голос
/ 18 апреля 2011

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

Входной файл имеет три строки с 3,5 и 7 повторениями «pq» соответственно. Выражения> = 3,> = 5 работают нормально, но выражение «от 3 до 5» {3,5} также показывает строку с семью повторениями.

DEV /> cat input.txt
pq -- One occurance of pq
pqpqpqpqpq -five occurances of pq
pqpqpqpqpqpqpq -- seven occurances of pq


DEV /> grep "\(pq\)\{3,\}" input.txt
pqpqpqpqpq -five occurances of pq
pqpqpqpqpqpqpq -- seven occurances of pq


DEV /> grep "\(pq\)\{5\}" input.txt
pqpqpqpqpq -five occurances of pq
pqpqpqpqpqpqpq -- seven occurances of pq

DEV /> grep "\(pq\)\{3,5\}" input.txt
pqpqpqpqpq -five occurances of pq
pqpqpqpqpqpqpq -- seven occurances of pq

Я что-то не так делаю или это ожидаемое поведение?

Если это ожидаемое поведение (поскольку строка с 7 PQ имеет 3-5 PQ),

1) в каких случаях применяются максимальные повторения? Какая разница между {3,5} и {3,} (больше 3)?

2) Я могу привязать свои регулярные выражения к «^», но что если моя строка не заканчивается на «pq» и имеет больше текста?

Ответы [ 2 ]

2 голосов
/ 18 апреля 2011

Если в строке есть семь повторений чего-либо, следовательно, она также содержит от 3 до 5 повторений этого события и в нескольких точках, не менее.

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

Практическая разница между /X{3,}/ и /X{3,5}/ состоит в том, как долго соответствует строка - экстент (или интервал)матч.Если все, что вы ищете, это булевы ответы «да / нет» и в вашем шаблоне нет ничего более, это не имеет большого значения;на самом деле, умеренно умный механизм регулярных выражений вернется рано, если узнает, что это безопасно.

Один из способов увидеть разницу - это GNU grep ‑o или -Только для соответствия опция.Наблюдайте:

$ echo 123456789 | egrep -o '[0-9]{3}'
123
456
789
$ echo 123456789 | egrep -o '[0-9]{3,}'
123456789
$ echo 123456789 | egrep -o '[0-9]{3,5}'
12345
6789
$ echo 123456789 | egrep -o '[0-9]{3,5}[2468]'
123456
$ echo 123456790 | egrep -o '[0-9]{3,5}[13579]'
12345
6789

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

$ perl -Mre=debug -le 'print $& while 1234567890 =~ /\d{3,5}[13579]/g'
Compiling REx "\d{3,5}[13579]"
Final program:
   1: CURLY {3,5} (4)
   3:   DIGIT (0)
   4: ANYOF[13579][] (15)
  15: END (0)
stclass DIGIT minlen 4 
Matching REx "\d{3,5}[13579]" against "1234567890"
Matching stclass DIGIT against "1234567" (7 chars)
   0 <> <1234567890>         |  1:CURLY {3,5}(4)
                                  DIGIT can match 5 times out of 5...
   5 <12345> <67890>         |  4:  ANYOF[13579][](15)
                                    failed...
   4 <1234> <567890>         |  4:  ANYOF[13579][](15)
   5 <12345> <67890>         | 15:  END(0)
Match successful!
12345
Matching REx "\d{3,5}[13579]" against "67890"
Matching stclass DIGIT against "67" (2 chars)
   5 <12345> <67890>         |  1:CURLY {3,5}(4)
                                  DIGIT can match 5 times out of 5...
  10 <1234567890> <>         |  4:  ANYOF[13579][](15)
                                    failed...
   9 <123456789> <0>         |  4:  ANYOF[13579][](15)
                                    failed...
   8 <12345678> <90>         |  4:  ANYOF[13579][](15)
   9 <123456789> <0>         | 15:  END(0)
Match successful!
6789
Freeing REx: "\d{3,5}[13579]"

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

$ perl -le 'print $& while 1234567890 =~ /\d{3}(?=[13579])/g'
234
678
$ perl -le 'print $& while 1234567890 =~ /\d{3,5}(?=[13579])/g'
1234
5678
% perl -le 'print $& while 1234567890 =~ /\d{3,}(?=[13579])/g'
12345678

Так что, когда у вас есть вещи, которые должны прийти позже, это может сделатьбольшая разница.Когда вы просто решаете, соответствует ли вся строка чему-либо, это может быть не так важно.

1 голос
/ 18 апреля 2011

Это ожидаемое поведение. Строка «pqpqpqpqpqpqpq» на самом деле имеет от трех до пяти повторений «pq», а затем еще несколько для хорошей меры. Вы можете попытаться закрепить свое регулярное выражение, например, ^\(pq\)\{3,5\}$.


Изменить для соответствия отредактированному вопросу:

  1. Максимум применим во всех ситуациях. Происходит следующее: grep сопоставляет 5 из 7 повторений «pq» (скорее всего, первые пять), и, поскольку он нашел совпадение, он печатает строку.
  2. Вам нужно будет найти способ изменить свое регулярное выражение, чтобы оно соответствовало тому, что вы хотите, и не совпадало с тем, что вы не делаете. Например, чтобы сопоставить строку, начинающуюся с 3–5 повторений «pq», вы можете сделать что-то вроде этого: ^\(pq\){3,5}\($|[^p]|p$|p[^q]\). Это соответствует 3–5 «pq», за которыми сразу же следует конец строки или любой символ, отличный от «p» или «p», следующий за концом строки или «p» -followed- по-любому-персонажа-другой-чем- "д".
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...