Python递归正则匹配平衡括号并替换LaTeX注释的问题
用Python正则处理带嵌套括号的LaTeX注释命令替换
问题分析
你需要替换LaTeX中的三种命令:
\ins{who}{what}→ 保留what\rem{who}{what}→ 替换为空字符串\rpl{who}{whatold}{whatnew}→ 保留whatnew
之前使用的PCRE2递归正则(如(?1)引用编号组)在Python的regex库中不适用,因为该库要求使用命名组递归语法而非编号组递归。
解决方案:使用命名递归组匹配平衡括号
Python第三方库regex支持递归正则,只需将递归部分改为命名组引用的形式。以下是两种实现方式:
方式一:合并正则统一处理(推荐)
将三个命令的匹配逻辑合并到一个正则中,通过替换函数根据命令类型返回对应内容:
import regex def process_latex_commands(text): # 定义包含递归平衡括号匹配的正则模式 pattern = r''' \\(ins|rem|rpl) # 匹配命令类型:ins/rem/rpl \{[a-z]{2}\} # 匹配who部分(固定两位小写字母) (?: # 匹配第一个内容块(适用于ins/rem) \{(?P<content>(?:[^{}]|(?P<balanced>\{(?:[^{}]|(?P>balanced))*\}))*)\} # 可选的第二个内容块(仅适用于rpl) (?:\{(?P<new_content>(?:[^{}]|(?P>balanced))*)\})? ) ''' def replace_handler(match): cmd_type = match.group(1) if cmd_type == 'ins': return match.group('content') elif cmd_type == 'rem': return '' elif cmd_type == 'rpl': return match.group('new_content') return match.group(0) # 默认返回原内容,避免漏匹配 # 启用VERBOSE模式忽略注释和空格,同时支持递归 return regex.sub(pattern, replace_handler, text, flags=regex.VERBOSE) # 测试示例 test_text = 'Velit sed ullamcorper morbi tincidunt ornare. Lorem dolor sed viverra ipsum nunc aliquet bibendum enim.\\rpl{dd}{ Pellentesque \\qtyrange{10}{20}{\\celsius} habitant morbi \\qtyrange{10}{20}{\\celsius} tristique senectus \\gls{abc}.}{Some new text with \\qtyrange{10}{20}{\\celsius} and more \\gls{cdf}.' result = process_latex_commands(test_text) print(result)
方式二:分正则单独处理
如果需要更清晰的拆分逻辑,可以分别为三个命令编写正则:
import regex text = 'Velit sed ullamcorper morbi tincidunt ornare. Lorem dolor sed viverra ipsum nunc aliquet bibendum enim.\\rpl{dd}{ Pellentesque \\qtyrange{10}{20}{\\celsius} habitant morbi \\qtyrange{10}{20}{\\celsius} tristique senectus \\gls{abc}.}{Some new text with \\qtyrange{10}{20}{\\celsius} and more \\gls{cdf}.' # 处理\ins命令 ins_pattern = r'\\ins\{[a-z]{2}\}\{(?P<content>(?:[^{}]|(?P<balanced>\{(?:[^{}]|(?P>balanced))*\}))*)\}' text = regex.sub(ins_pattern, r'\g<content>', text) # 处理\rem命令 rem_pattern = r'\\rem\{[a-z]{2}\}\{(?P<content>(?:[^{}]|(?P<balanced>\{(?:[^{}]|(?P>balanced))*\}))*)\}' text = regex.sub(rem_pattern, '', text) # 处理\rpl命令 rpl_pattern = r'\\rpl\{[a-z]{2}\}\{(?P<old>(?:[^{}]|(?P<balanced>\{(?:[^{}]|(?P>balanced))*\}))*)\}\{(?P<new>(?:[^{}]|(?P>balanced))*)\}' text = regex.sub(rpl_pattern, r'\g<new>', text) print(text)
关键说明
- 平衡括号匹配逻辑:
(?P<balanced>\{(?:[^{}]|(?P>balanced))*\})是核心,它通过递归调用命名组balanced,可以正确匹配任意深度嵌套的大括号。 - 语法差异:Python的
regex库不支持PCRE的(?1)编号组递归,必须使用(?P>balanced)这种命名组引用的形式。 - 依赖要求:必须使用第三方
regex库(而非Python标准库re),因为标准库不支持递归正则。
内容的提问来源于stack exchange,提问作者atapaka
相关产品推荐
相关产品推荐

