Почему поиск в регулярном выражении в подстроке "не полностью эквивалентен разрезанию строки" в Python?
Как указано в документации, использование regex.search(string, pos, endpos)
не полностью эквивалентно разрезанию строки, т.е. regex.search(string[pos:endpos])
. Он не будет выполнять регулярное выражение, как если бы строка начиналась с pos
, поэтому ^
не соответствует началу подстроки, но соответствует только реальному началу всей строки. Однако $
соответствует либо концу подстроки, либо всей строке.
>>> re.compile('^am').findall('I am falling in code', 2, 12)
[] # am is not at the beginning
>>> re.compile('^am').findall('I am falling in code'[2:12])
['am'] # am is the beginning
>>> re.compile('ing$').findall('I am falling in code', 2, 12)
['ing'] # ing is the ending
>>> re.compile('ing$').findall('I am falling in code'[2:12])
['ing'] # ing is the ending
>>> re.compile('(?<= )am').findall('I am falling in code', 2, 12)
['am'] # before am there is a space
>>> re.compile('(?<= )am').findall('I am falling in code'[2:12])
[] # before am there is no space
>>> re.compile('ing(?= )').findall('I am falling in code', 2, 12)
[] # after ing there is no space
>>> re.compile('ing(?= )').findall('I am falling in code'[2:12])
[] # after ing there is no space
>>> re.compile(r'\bm.....').findall('I am falling in code', 3, 11)
[]
>>> re.compile(r'\bm.....').findall('I am falling in code'[3:11])
['m fall']
>>> re.compile(r'.....n\b').findall('I am falling in code', 3, 11)
['fallin']
>>> re.compile(r'.....n\b').findall('I am falling in code'[3:11])
['fallin']
Мои вопросы... Почему это не согласуется между началом и окончанием матча? Почему использование pos
и endpos
обрабатывает конец как реальный конец, но начало/начало не рассматривается как реальное начало/начало?
Есть ли какой-либо подход, который позволяет использовать pos
и endpos
подражать разрезанию? Поскольку Python копирует строку при разрезании вместо простой ссылки на старую, было бы более эффективно использовать pos
и endpos
вместо нарезки при работе с большой строкой несколько раз.
Ответы
Ответ 1
Аргумент начальной позиции pos
особенно полезен, например, для лексических анализаторов. Разница в производительности между нарезкой строки с помощью [pos:]
и использованием параметра pos
может показаться незначительной, но это, конечно, не так; см., например, этот отчет об ошибке в JsLex lexer.
Действительно, ^
совпадает с реальным началом строки; или, если указано MULTILINE
, также в начале строки; это также по дизайну, так что сканер, основанный на регулярных выражениях, может легко различать реальный начало строки/начало ввода и только некоторую другую точку на линии/внутри входа.
Заметьте, что вы также можете использовать функцию regex.match(string[, pos[, endpos]])
для привязки соответствия к начальной строке или в позиции, указанной pos
; таким образом, вместо того, чтобы делать
>>> re.compile('^am').findall('I am falling in code', 2, 12)
[]
вы, как правило, использовали сканер как
>>> match = re.compile('am').match('I am falling in code', 2, 12)
>>> match
<_sre.SRE_Match object; span=(2, 4), match='am'>
а затем установите pos
в match.end()
(который в этом случае возвращает 4) для последовательных операций сопоставления.
Совпадение должно начинаться точно с pos
:
>>> re.compile('am').match('I am falling in code', 1, 12)
>>>
(Обратите внимание, что .match
привязан в начале ввода как будто неявным ^
, но не до конца ввода, действительно, это часто является источником ошибок, поскольку люди считают, что совпадение имеет как неявное ^
и $
- Python 3.4 добавил regex.fullmatch
, который делает это)
Как почему параметр endpos
не согласуется с pos
, который я точно не знаю, но это также имеет для меня какое-то значение, так как в Python 2 нет fullmatch
и существует привязка к $
- единственный способ обеспечить соответствие всего диапазона.
Ответ 2
Это звучит как ошибка в Python, но если вы хотите сделать фрагмент по ссылке вместо копирования строк, вы можете использовать встроенный Python buffer
.
Например:
s = "long string" * 100
buf = buffer(s)
substr = buf([5:15])
Это создает подстроку без копирования данных, поэтому она должна обеспечивать эффективное разделение больших строк.