Как правильно смотреть в будущее с LPeg
Чтобы соответствовать строке, начинающейся с dog
, с последующим cat
(но не потребляющий cat
), это работает:
local lpeg = require 'lpeg'
local str1 = 'dogcat'
local patt1 = lpeg.C(lpeg.P('dog')) * #lpeg.P('cat')
print(lpeg.match(patt1, str1))
Выход: dog
Чтобы соответствовать строке, начинающейся с dog
с последующими последовательностями символов, затем cat
(но не потребляя это), как регулярное выражение взгляда (dog.+?)(?=cat)
Я попробовал это:
local str2 = 'dog and cat'
local patt2 = lpeg.C(lpeg.P("dog") * lpeg.P(1) ^ 1) * #lpeg.P("cat")
print(lpeg.match(patt2, str2))
Мой ожидаемый результат dog and
, но это возвращает nil
,
Если я выбрасываю часть lookahead (то есть, используя шаблон lpeg.C(lpeg.P("dog") * lpeg.P(1) ^ 1)
), он может соответствовать всей строке успешно. Это означает * lpeg.P(1) ^ 1
часть соответствует любой последовательности символов правильно, не так ли?
Как это исправить?
1 ответ
Вы должны отрицать "кошку" в каждой позиции в предвкушении, которая может соответствовать:
local patt2 = lpeg.C(lpeg.P"dog" * (lpeg.P(1)-lpeg.P"cat") ^ 1) * #lpeg.P"cat"
Я думаю, что стоит подключить отладчик, над которым я работал ( pegdebug), так как он помогает в подобных случаях. Вот вывод, который он генерирует для исходного выражения lpeg:
+ Exp 1 "d"
+ Dog 1 "d"
= Dog 1-3 "dog"
+ Separator 4 " "
= Separator 4-11 " and cat"
+ Cat 12 ""
- Cat 12
- Exp 1
Вы можете видеть, что выражение Separator "съедает" все символы, включая "cat", и нечего сопоставлять P"cat"
,
Вывод для измененного выражения выглядит следующим образом:
+ Exp 1 "d"
+ Dog 1 "d"
= Dog 1-3 "dog"
+ Separator 4 " "
= Separator 4-8 " and "
+ Cat 9 "c"
= Cat 9-11 "cat"
= Exp 1-8 "dog and "
/ Dog 1 0
/ Separator 4 0
/ Exp 1 1 "dog and "
Вот полный сценарий:
require 'lpeg'
local peg = require 'pegdebug'
local str2 = 'dog and cat'
local patt2 = lpeg.P(peg.trace { "Exp";
Exp = lpeg.C(lpeg.V"Dog" * lpeg.V"Separator") * #lpeg.V"Cat";
Cat = lpeg.P("cat");
Dog = lpeg.P("dog");
Separator = (lpeg.P(1) - lpeg.P("cat"))^1;
})
print(lpeg.match(patt2, str2))