正则表达式移除非嵌套<mrow>标签首尾括号的问题排查
从非嵌套
<mrow>标签提取内容并移除首尾括号的正则方案 问题背景
需要从类似<mrow>(<mn>1000001</mn>)</mrow>的字符串中提取内部的<mn>1000001</mn>,要求仅处理非嵌套的<mrow>...</mrow>标签,同时移除标签首尾可能存在的括号。
最初使用的正则模式:
<mrow[^\>]*>\(?((?:(?!<mrow>[^\>]*>|<\/mrow>).)*)\)?<\/mrow>
预期替换结果为<mn>1000001</mn>,但实际得到<mn>1000001</mn>),残留了右括号,处理复杂数学公式时该问题仍存在。
问题原因
原正则的核心问题在于贪婪匹配导致右括号被捕获组包含:
- 中间的捕获组
(?:(?!<mrow>[^\>]*>|<\/mrow>).)*是贪婪模式,会尽可能匹配所有不触发负向预查的字符,包括末尾的右括号) - 后面的
\)?因为捕获组已经吃掉了右括号,没有可匹配的字符,所以无法移除这个括号
正确正则实现
调整正则结构,将可选括号移到捕获组前后,并使用非贪婪模式确保捕获组不会包含末尾的括号,同时增加空白处理提升鲁棒性:
<mrow[^>]*>\s*\(?\s*((?:(?!<mrow[^>]*>|</mrow>).)*?)\s*\)?\s*</mrow>
正则解析
<mrow[^>]*>:匹配任意属性的<mrow>起始标签\s*\(?\s*:匹配可能的前置空白+可选左括号((?:(?!<mrow[^>]*>|</mrow>).)*?):非贪婪捕获内部内容,负向预查确保不匹配嵌套的<mrow>标签\s*\)?\s*:匹配可能的后置空白+可选右括号</mrow>:匹配结束标签
使用示例
以原字符串为例,替换时引用捕获组$1(不同语言可能用\1或其他语法),即可得到干净的<mn>1000001</mn>。
对于更复杂的公式如<mrow> ( <mn>123</mn> + <mn>456</mn> ) </mrow>,同样能正确提取<mn>123</mn> + <mn>456</mn>。
内容的提问来源于stack exchange,提问作者Xavier Junqué
相关产品推荐
相关产品推荐

