如何将指定正则转换为LPEG分割模式?适配SemVer约束
正则转LPEG分割模式的问题与解决
问题描述
我需要将正则模式{ *(?<!-)[, ](?!-) *}转换为LPEG模式,用作分割规则——可以把2.5 2.6/2.5, 2.6分割成2.5和2.6,但遇到-时不执行分割,这是SemVer版本约束识别的一部分。我用了LPEG文档里的split函数:
local function split (str, sep) sep = l.P(sep) local elem = l.C((1 - sep)^0) local p = l.Ct(elem * (sep * elem)^0) -- make a table capture return p:match(str) end
我的初步实现能处理带逗号的情况:
local h, sp = l.P'-', l.P' ' patt = sp^0 * (-h * l.S' ,' - h) * sp^0 split('2.5, 2.6', patt) -- 有效 split('2.5 2.6', patt) -- 失败,因首个sp^0匹配所有内容
但仅含空格的场景会失败,其他尝试还出现了无限循环。请问如何在保留原正则约束的同时解决该问题?
问题分析与修复
核心问题在于原分割模式的逻辑缺陷:sp^0会优先匹配所有空格,导致纯空格分隔的场景下,分隔符的核心匹配逻辑根本没机会触发。另外,原模式的否定逻辑可以更精准地对应正则的(?<!-)和(?!-)(负前后瞻)。
正确的LPEG分割模式实现
我们需要把分隔符逻辑调整为:前后不能是-的逗号或空格,同时前后可以有任意数量的空格,但必须确保核心分隔符(逗号/空格)存在。
修改后的完整代码如下:
local l = require'lpeg' local function split(str, sep) sep = l.P(sep) local elem = l.C((1 - sep)^0) local p = l.Ct(elem * (sep * elem)^0) return p:match(str) end -- 构建符合要求的分隔符模式 local dash = l.P'-' -- 核心分隔符:逗号或空格,且前后都不是减号,对应正则的(?<!-)[, ](?!-) local sep_core = (-dash) * l.S', ' * (-dash) -- 完整分隔符:核心分隔符前后可带任意空格,同时处理连续空格场景避免无限循环 local patt = l.P{ l.P' '^0 * sep_core * l.P' '^0 + -- 匹配连续空格后递归,确保最终能定位到有效核心分隔符 l.P' '^1 * l.V(1) } -- 测试用例验证 print(unpack(split('2.5, 2.6', patt))) -- 输出:2.5 2.6 print(unpack(split('2.5 2.6', patt))) -- 输出:2.5 2.6 print(unpack(split('2.5-2.6', patt))) -- 输出:2.5-2.6(不分割) print(unpack(split('2.5 , 2.6', patt))) -- 输出:2.5 2.6 print(unpack(split('2.5 - 2.6', patt))) -- 输出:2.5 - 2.6(不分割)
关键说明
sep_core:用LPEG的(-dash)实现正则的负前后瞻效果,确保分隔符的前后都不是减号。- 递归分隔符模式:通过递归规则处理连续空格的场景,同时用
l.P' '^1确保每次递归都至少匹配一个空格,避免无限循环。 - 空格匹配逻辑:将空格匹配放在核心分隔符的前后,既保留了原正则允许分隔符前后带任意空格的规则,又避免了纯空格吞掉所有内容的问题。
内容的提问来源于stack exchange,提问作者Optimum
相关产品推荐
相关产品推荐

