LPeg如何匹配奇数整数?R"09"^0 * S"13579"模式为何失效
LPeg 匹配奇数整数的实现方案
原模式失效原因
你写的模式R"09"^0 * S"13579"无法匹配成功,核心原因是LPeg基于PEG(解析表达文法)实现,重复匹配规则默认是贪婪且无回溯的:R"09"^0会一次性消耗掉所有连续的数字字符,匹配到数字串末尾后没有剩余字符留给后续的S"13579"规则去匹配末位奇数,自然返回匹配失败。
注意:LPeg 没有正则实现里的自动回溯机制,一旦前面的规则匹配消耗了字符,不会自动回退释放字符给后续规则匹配,因此不能直接照搬正则
\d*[13579]的写法。
正确实现代码
无符号奇数整数匹配
local lpeg = require"lpeg" local R, S, C = lpeg.R, lpeg.S, lpeg.C -- 匹配无符号奇数整数,匹配成功返回捕获到的数字串,否则返回nil local unsigned_odd = C( (R"09" - S"13579")^0 -- 匹配0个或多个非奇数数字(0/2/4/6/8),不会消耗末位奇数 * S"13579" -- 匹配最后一位奇数字符 ) * -R"09" -- 断言匹配位置后无剩余数字,避免只匹配长数字的奇数后缀
带符号奇数整数匹配
如果需要支持正负号前缀,在模式最前面加上可选符号匹配即可:
local signed_odd = S"+-"^-1 * unsigned_odd
模式逻辑说明
- 前缀部分
(R"09" - S"13579")^0只匹配偶数字,永远不会吃掉最后一位的奇数,从根源上避免了原模式里前缀贪婪消耗所有字符的问题 - 末尾的
-R"09"是负向断言,保证匹配到的是完整的数字串,不会出现比如1234只匹配到后缀3的错误情况 - 该模式兼容前导零场景,比如
00013、05这类合法奇数格式都可以正常匹配
内容的提问来源于stack exchange,提问作者Jason Wang
相关产品推荐
相关产品推荐

