Python处理类XML文本的正则匹配不全、替换失效问题解析
正则重构类XML结构的问题修复方案
1. 解决arr块跨换行匹配、避免全文件单次匹配的问题
原正则之所以会出现开启DOTALL后全文件单次匹配的问题,核心是两个写法缺陷:
- 内容匹配用了贪婪规则:原内容捕获部分是
(.*),开启DOTALL让.支持匹配换行后,会从第一个开标签一直抓到文件里最后一个符合格式的闭标签,自然把整个文件当成单次匹配。 - 开闭标签没有绑定:原正则的闭标签部分是独立的捕获组,没有和开标签的类型做绑定,会出现开标签是arr,却匹配到文件末尾任意类型闭标签的越界问题。
修正后的匹配逻辑:
- 用反向引用绑定开闭标签类型:开标签的类型作为第一个捕获组,闭标签用
\1反向引用,保证开闭标签的类型完全一致,不会跨类型抓内容。 - 内容捕获改为非贪婪匹配:把原来的
(.*)换成(.*?),不管是否支持换行匹配,都会在碰到第一个符合要求的同类型闭标签时立即停止捕获。 - 开标签的属性部分做精准匹配:把
.*="换成\s+name="([^"]+)",避免贪婪匹配导致的开标签识别过长问题。
最终可实现独立块匹配的正则表达式为:<(str|date|arr|int|long)\s+name="([^"]+)">(.*?)</\1>
编译时开启re.DOTALL参数,即可实现arr块跨换行匹配,且每个块独立捕获、不会跨块越界。
2. 解决正则替换完全不生效的问题
你写的代码存在两个逻辑问题,哪怕替换规则写的是固定字符串也不会看到效果:
re.sub()不会修改原字符串,它的返回值才是替换完成后的新文本。你之前执行完p.sub(...)没有把返回值赋值给变量,之后打印的还是读取进来的原始内容,自然看不到任何变化。- 编译正则时没有传入DOTALL参数,碰到带换行的arr标签根本无法匹配,自然不会触发替换逻辑。
修正后的完整可运行代码:
from re import compile import re # 编译正则,开启DOTALL支持换行匹配 pattern = compile( r'<(str|date|arr|int|long)\s+name="([^"]+)">(.*?)</\1>', flags=re.DOTALL ) # 用上下文管理器读取文件,指定编码避免乱码 with open("file.txt", "r", encoding="utf-8") as f: content = f.read() # *关键:接收sub的返回值,拿到替换后的新内容* new_content = pattern.sub(r'<\2>\3</\2>', content) # 若需要写回原文件,可追加以下代码 # with open("file.txt", "w", encoding="utf-8") as f: # f.write(new_content) print(new_content)
可选优化:清理arr块内的内嵌标签
你期望的输出里,arr标签替换后的内容需要去掉内嵌的<str>标签尖括号,只保留内部文本,可以把替换逻辑改成自定义函数,在替换时自动清理内嵌标签:
def process_match(match): _, attr_name, inner_content = match.groups() # 去掉内容里所有的内嵌尖括号标签 clean_content = re.sub(r'<[^>]+>', '', inner_content) return f'<{attr_name}>{clean_content}</{attr_name}>' new_content = pattern.sub(process_match, content)
执行后即可得到完全符合预期的输出结构。
内容的提问来源于stack exchange,提问作者lakeviking
相关产品推荐
相关产品推荐

