如何用Lua模式匹配正确解析带嵌套的MediaWiki参数语法?
解决MediaWiki参数转Lua的模式匹配问题
Lua的模式匹配本身不支持递归匹配,没法用单一正则/模式处理带嵌套大括号的MediaWiki参数语法。要解决你遇到的三个问题,得用层级计数+循环遍历的方式处理,具体思路如下:
1. 准确定位完整的{{{...}}}块
核心是跟踪大括号的层级,找到每个参数块的完整范围:
- 遍历字符串,先定位所有
{{{的起始位置 - 从起始位置后开始计数:每遇到
{层级+1,遇到}层级-1 - 当层级回到0时,说明找到了对应的闭合
}}},此时提取整个参数块
示例Lua代码:
function extractParamBlocks(text) local blocks = {} local idx = 1 local len = #text while idx <= len do -- 找到下一个{{{的起始位置 local start = text:find("{{{", idx) if not start then break end local level = 3 -- 初始三个左大括号,层级为3 local current = start + 3 -- 遍历找闭合的}}} while current <= len do local char = text:sub(current, current) if char == "{" then level = level + 1 elseif char == "}" then level = level - 1 -- 层级归0,说明找到完整闭合 if level == 0 then local block = text:sub(start, current) table.insert(blocks, block) idx = current + 1 break end end current = current + 1 end -- 若未找到闭合,跳过当前{{{继续查找 if not current then idx = start + 3 end end return blocks end
2. 拆分参数名与带嵌套的默认值
提取到完整参数块后,需要拆分参数名和默认值,同样要通过层级计数判断顶层的|分隔符(避免误拆分嵌套内容里的|):
- 先去掉参数块外层的
{{{和}}},得到内部内容 - 遍历内部内容,跟踪层级,只在层级为0时识别分隔符
| - 分隔后分别提取参数名和默认值
示例Lua代码:
function splitParamParts(block) -- 去掉外层的{{{和}}} local content = block:sub(4, #block - 3) local paramName, defaultValue local level = 0 local splitPos = nil for i = 1, #content do local char = content:sub(i, i) if char == "{" then level = level + 1 elseif char == "}" then level = level - 1 elseif char == "|" and level == 0 then splitPos = i break end end if splitPos then paramName = content:sub(1, splitPos - 1):gsub("^%s+", ""):gsub("%s+$", "") -- 去首尾空格 defaultValue = content:sub(splitPos + 1):gsub("^%s+", ""):gsub("%s+$", "") else paramName = content:gsub("^%s+", ""):gsub("%s+$", "") defaultValue = nil end return paramName, defaultValue end
3. 递归转换为Lua兼容语法
对于默认值里嵌套的MediaWiki参数,需要递归处理,最终转换为Lua的短路求值语法(比如args.param or (args.alias or "default")):
function convertToLuaSyntax(block, argsName) argsName = argsName or "args" -- 默认用args作为参数表名 local paramName, defaultValue = splitParamParts(block) if not defaultValue then return string.format("%s.%s", argsName, paramName) end -- 检查默认值是否也是MediaWiki参数块 if defaultValue:find("^{{{") then local nestedLua = convertToLuaSyntax("{{{" .. defaultValue .. "}}}", argsName) return string.format("%s.%s or (%s)", argsName, paramName, nestedLua) else -- 默认值是普通字符串,转义引号 local escapedDefault = defaultValue:gsub('"', '\\"') return string.format('%s.%s or "%s"', argsName, paramName, escapedDefault) end end
对应解决你的三个具体问题
- 问题1(嵌套匹配不完整):通过层级计数准确找到每个参数块的闭合位置,不会在嵌套中途截断
- 问题2(移除大括号限制后匹配异常):只识别顶层的
|分隔符,不会误拆分嵌套内容里的分隔符 - 问题3(多参数匹配溢出):每个参数块的起始和闭合位置独立计算,不会跨块匹配相邻的参数
内容的提问来源于stack exchange,提问作者Lemondoge
相关产品推荐
相关产品推荐

