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

Почему поиск в регулярном выражении в подстроке "не полностью эквивалентен разрезанию строки" в 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 вместо нарезки при работе с большой строкой несколько раз.

4b9b3361

Ответ 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])

Это создает подстроку без копирования данных, поэтому она должна обеспечивать эффективное разделение больших строк.