Порядок операций регулярного выражения для ленивого оператора - PullRequest
1 голос
/ 05 мая 2020

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

exampleString = '    something               '

import re

searchObject = re.compile(r'\s*(.*?)\s*')
subObject = searchObject.sub(r'\1', exampleString)

print(subObject)

Это сделало то, что я хотел, но меня беспокоило пространство между ними. Поэтому я попробовал вместо этого

exampleString2 = '    somet hing               '

, и он по-прежнему работал так, как я хотел.

Мой вопрос: как не жадный оператор решает пройти через среднее пространство? Разве он не должен возвращать ' somet '?

Если он читает регулярное выражение слева направо, он удовлетворяет .*?, прежде чем он удовлетворяет последнему \s*, поэтому он выберет самую маленькую строку из чего-либо, пока он может соответствовать пробелу, верно?

Ответы [ 2 ]

0 голосов
/ 05 мая 2020

re.sub продолжает заменять часть строки, которая еще не совпала, пока не достигнет счетчика или конца строки, затем он вернет оставшуюся строку.

Также ваш шаблон может соответствовать нулевым символам.

>>> pattern = re.compile(r'\s*(.*?)\s*')
>>> re.sub(pattern, r"\1", '   foo bar   ' , count=1)
'foobar   '
>>> re.sub(pattern, r"\1", 'foobar   ' , count=1)
 'foobar'
>>> re.sub(pattern, r"\1", '   foo bar   ' )
 'foobar'

Если это соответствует вашим потребностям, вы можете упростить свое регулярное выражение.

>>> re.sub(r"\s*", r"", '   foo bar   ' )
 'foobar'

Если вы хотите заменить только пробел в конце строки, используйте следующее.

>>> re.sub(r"^\s*|\s*$", r"", '   foo bar   ' )
 'foo bar'
0 голосов
/ 05 мая 2020

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

Например, вот как выглядят совпадения в настоящее время: https://regex101.com/r/AzOrJZ/2

Вы можете получить, как это выглядит после одного совпадения, следуя этим инструкциям:

Как я могу заменить регулярное выражение только один раз в Python?

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

\s*(\S+(?:\s+\S+)*)\s*

Это по существу соответствует всем ведущим пробельным символам \s+ затем группирует все непробельные символы \S+, за которыми следует один или несколько пробелов с непробельным (\s+\S+)*. Как только все непробельные символы совпадают, он соответствует конечному пробелу.

https://regex101.com/r/AzOrJZ/4

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