Подтвердить что ты не робот

Непоследовательность между $и ^ в regex при использовании аргументов start/end для re.search?

Из того, что я прочитал, ^ должен соответствовать началу строки, а $ конец. Однако, с re.search(), похоже, что поведение ^ продолжает работать нормально, а $ "breaks". Пример:

>>> a = re.compile( "^a" )
>>> print a.search( "cat", 1, 3 )
None

Это кажется мне правильным - 'a' не находится в начале строки, даже если она находится в начале поиска.

>>> a = re.compile( "a$" )
>>> print a.search( "cat", 0, 2 )
<_sre.SRE_Match object at 0x7f41df2334a8>

Это кажется мне неправильным или, по крайней мере, непоследовательным.

Документация в модуле re явно указывает, что поведение ^ не изменяется из-за аргументов start/end для re.search, но никаких изменений в поведении не упоминается для $ (что я видно).

Может ли кто-нибудь объяснить, почему все было спроектировано таким образом и/или предложило удобное обходное решение?

В обходном пути я хотел бы создать регулярное выражение, которое всегда соответствует концу строки, даже если кто-то использует аргумент end для re.search.

И почему был создан re.search такой, что:

s.search( string, endPos=len(string) - 1 )

совпадает с

s.search( string[:-1] )

когда

s.search( string, startPos=1 )

явно и намеренно не совпадает с

s.search( string[1:] )

Кажется, что проблема с несогласованностью между ^ и $ невелика и больше несогласованности в функции re.search.

4b9b3361

Ответ 1

Краткий ответ

Используйте \A to и \Z для соответствия началу или концу строки. Соответствующие строки из модуля re docs:

6.2.1. Синтаксис регулярного выражения

\AСовпадает только в начале строки.

\ZСовпадает только в конце строки.

Предостережение о endpos

Это не сработает ", даже если кто-то использует аргумент end для re.search". В отличие от параметра "start" pos, который просто отмечает начальную точку, параметр endpos означает, что поиск (или совпадение) будет выполняться только на части строки (выделено курсором):

6.2.3. Объекты регулярного выражения

regex.search(string[, pos[, endpos]])

Необязательный параметр endpos ограничивает расстояние поиска строки; это будет как если бы строка была endpos длинными символами, [...] rx.search(string, 0, 50) эквивалентно rx.search(string[:50], 0).

\Z соответствует концу искомой строки, что в точности соответствует endpos.

Фон

Более знакомые ^ и $ не делают то, что вы думаете:

^(Caret.) Соответствует началу строки, а в MULTILINE также соответствует сразу после каждой новой строки.

$Соответствует концу строки или непосредственно перед новой строкой в ​​конце строки, а в MULTILINE режим также соответствует перед новой строкой. foo соответствует как "foo", так и "foobar", а регулярное выражение foo$ соответствует только "foo". Более интересно, поиск foo.$ в 'foo1\nfoo2\n' обычно соответствует "foo2", но "foo1" в MULTILINE; поиск одного $ в 'foo\n' найдет два (пустых) совпадения: один непосредственно перед символом новой строки и один в конце строки.

Регулярные выражения Python находятся под сильным влиянием Perl, что расширяет старые возможности grep с помощью своего собственного хозяина. Это включало многострочное сопоставление, в котором возник вопрос о метасимволах, таких как ^: Соответствовало ли это началу строки или началу строки? Когда grep соответствует только одной строке за раз, это были эквивалентные понятия.

Как вы можете видеть, ^ и $ в конечном итоге пытались сопоставить все "start-like" и "end-ish". Perl представил новые escape-последовательности \A и \Z (нижний регистр), чтобы соответствовать только началу строки и концу строки.

Эти escape-последовательности были приняты Python, но с одним отличием: Python не принял Perl \Z (верхний регистр), который соответствовал как конца строки, так и специальной строки newline-before-end-string... что делает его не совсем партнером \A, который можно было бы ожидать.

(Я предполагаю, что Perl \Z с верхним расположением Python для последовательности, избегая однообразных регулярных выражений '\Apattern\z', которые были рекомендованы в таких книгах, как Perl Best Practices.)

История pos и endpos

Похоже, что странная "не на самом деле позиция начала-начала" значения pos столь же древняя, как и сам параметр:

  • Python 1.4 match function docs (25 октября 1996 г. --- возможно, предварительно предваряющий объект регулярного выражения) t показывает параметры pos или endpos.

  • Python 1.5 match метод docs (17 февраля 1998 г.) представляет как объект регулярного выражения, так и pos и endpos. В нем указано, что ^ будет соответствовать pos, хотя последующие версии предполагают, что это была опечатка. (Говоря о опечатках: Сам символ ^ отсутствует. Он пришел и ушел, пока наконец не появился навсегда (?) В Python 2.1.)

  • Python 1.5.1 match метод docs (14 апреля 1998 г.) вставить отсутствующий "нет", отменив предыдущий документы.

  • Python 1.5.1p1 match метод docs (06 августа 1998 г.) уточняет неожиданные эффекты pos. Они соответствуют описание Python 3.6.1 pos слово за слово... дайте или возьмите эту надоедливую ^ опечатку.

Я подозреваю, что многочисленные изменения в документах за пару месяцев выпусков исправлений ошибок отражают документы, догоняющие реальность - не изменения дизайна match (хотя у меня нет Python 1, чтобы проверить это).

python-dev архивы списков рассылки вернутся только к 1999 году, поэтому, если предыдущие сообщения не были сохранены в другом месте, я думаю, почему "вопрос требует угадать, кто написал этот код, и спрашивать их.

Ответ 2

В соответствии с документацией search() здесь:

Необязательный параметр endpos ограничивает время поиска строки; это будет так, как если бы строка была длинной символом endpos, поэтому будут найдены только символы из pos в endpos-1.

Итак, ваш синтаксис a.search("cat", 0, 2) эквивалентен a.search("ca"), который соответствует шаблону a$.

Ответ 3

Это кажется мне неправильным или, по крайней мере, непоследовательным.

Нет, интерпретация endpos согласуется с остальной частью Python, это начальная позиция pos, которая несовместима как документация объясняет

параметр pos дает индекс в строке, где поиск Начало; он по умолчанию равен 0. Это не совсем эквивалентно разрезанию Струна; символ "^" совпадает с реальным началом строка