Python正则re.sub批量追加文本仅替换奇数项的解决方法
问题描述
我有如下格式的多行字符串:
Front (A) Text1. (A) Text2. (A) Text3. (A) Text4. (A) Text5. End
注意:Text1、Text2等文本可能包含换行符。我希望在每个Text1、Text2等文本末尾追加字符串END。
用变量c表示上述多行字符串,我尝试使用正则re.sub实现该操作:
c = re.sub("\(A\)(.*?)\n\n\(A\)" , r"(A)\1 END\n\n(A)", c, flags=re.DOTALL)
但该操作仅替换了奇数序号的项,输出结果如下:
Front (A) Text1. END (A) Text2. (A) Text3. END (A) Text4. (A) Text5. End
最后一个项目可作为例外处理,我更关注为何仅每隔一个项目末尾追加了END。我认为原因是当第二个(A)被用作re.sub的匹配终点时,Python会将其排除在起始匹配点之外。请问该如何解决这个问题?
问题原因
你的判断完全正确。原正则\(A\)(.*?)\n\n\(A\)会匹配(A) TextX.加上后续空行和下一个(A),完成一次替换后,下一次匹配的起始位置会落在第二个(A)之后,直接跳过了中间的条目,所以只会处理奇数位置的内容。
解决方法
方案1:用正向预查避免消耗匹配内容
把正则里的第二个(A)改成正向预查,它不会被计入匹配的消耗部分,下一次匹配可以从这个位置重新开始。修改后的代码如下:
import re c = re.sub(r"\(A\)(.*?)(?=\n\n\(A\))", r"(A)\1 END", c, flags=re.DOTALL)
这里的(?=\n\n\(A\))是正向预查,只检查后面是否存在\n\n(A),但不会把这部分内容包含在匹配结果里,这样所有中间的(A)条目都会被处理。
方案2:统一处理所有(A)条目(包括最后一个)
如果想要连最后一个(A) Text5.也一起处理,可以调整正则,匹配所有以(A)开头,直到下一个(A)或者End前的内容:
import re c = re.sub(r"\(A\)(.*?)(?=\n\n\(A\)|\n\nEnd)", r"(A)\1 END", c, flags=re.DOTALL)
这个正则的(?=\n\n\(A\)|\n\nEnd)表示匹配到后面是\n\n(A)或者\n\nEnd的位置,这样所有(A)开头的条目都会被追加END。
内容的提问来源于stack exchange,提问作者Clement Yung
相关产品推荐
相关产品推荐

