根本原因
在 Python 3.5 之前,对 Python 中失败的捕获组进行反向引用re.sub
没有填充空字符串。这是bugs.python.org 上的错误 1519638 描述 https://bugs.python.org/issue1519638。因此,当对未参加比赛的组使用反向引用时会导致错误。
有两种方法可以解决该问题。
解决方案 1:添加空替代项以使可选组成为必需项
您可以替换所有可选的捕获组(这些结构如(\d+)?
)与强制性的和一个空的替代(即。(\d+|)
).
Here is 失败的例子 http://ideone.com/UVzXOQ:
import re
old = 'regexregex'
new = re.sub(r'regex(group)?regex', r'something\1something', old)
print(new)
更换一根线 http://ideone.com/11tcKq with
new = re.sub(r'regex(group|)regex', r'something\1something', old)
有用。
解决方案 2:在替换中使用 lambda 表达式并检查该组是否不存在None
如果您在另一个可选组中有可选组,则此方法是必要的。
您可以在替换部分使用 lambda 来检查组是否已初始化,而不是None
, with lambda m: m.group(n) or ''
. 在您的情况下使用此解决方案,因为在替换模式中有两个反向引用 - #3 和 #4,但是一些比赛 https://regex101.com/r/vD8zM5/2(参见匹配 1 和 3)没有初始化捕获组 3。发生这种情况是因为整个第一部分 -(\s*\{{2}funcA(ka|)\s*\|\s*([^}]*)\s*\}{2}\s*|)
- 未参加比赛,且内攻第3组(即([^}]*)
) just 即使添加空替代项后也不会填充.
re.sub(r'(?i)(\s*\{{2}funcA(ka|)\s*\|\s*([^\}]*)\s*\}{2}\s*|)\{{2}funcB\s*\|\s*([^\}]*)\s*\}{2}\s*',
r"\n | funcA"+str(n)+r" = \3\n | funcB"+str(n)+r" = \4\n | string"+str(n)+r" = \n",
text,
count=1)
应该重写为
re.sub(r'(?i)(\s*{{funcA(ka|)\s*\|\s*([^}]*)\s*}}\s*|){{funcB\s*\|\s*([^}]*)\s*}}\s*',
lambda m: r"\n | funcA"+str(n)+r" = " + (m.group(3) or '') + "\n | funcB" + str(n) + r" = " + (m.group(4) or '') + "\n | string" + str(n) + r" = \n",
text,
count=1)
See IDEONE演示 http://ideone.com/hiP30u
import re
text = r'''
{{funcB|param1}}
*some string*
{{funcA|param2}}
{{funcB|param3}}
*some string2*
{{funcB|param4}}
*some string3*
{{funcAka|param5}}
{{funcB|param6}}
*some string4*
'''
for n in (range(1,(text.count('funcB')+1))):
text = re.sub(r'(?i)(\s*\{{2}funcA(ka|)\s*\|\s*([^\}]*)\s*\}{2}\s*|)\{{2}funcB\s*\|\s*([^\}]*)\s*\}{2}\s*',
lambda m: r"\n | funcA"+str(n)+r" = "+(m.group(3) or '')+"\n | funcB"+str(n)+r" = "+(m.group(4) or '')+"\n | string"+str(n)+r" = \n",
text,
count=1)
assert text == r'''
| funcA1 =
| funcB1 = param1
| string1 =
*some string*
| funcA2 = param2
| funcB2 = param3
| string2 =
*some string2*
| funcA3 =
| funcB3 = param4
| string3 =
*some string3*
| funcA4 = param5
| funcB4 = param6
| string4 =
*some string4*
'''
print 'ok'