空字符串而不是不匹配的组错误
Empty string instead of unmatched group error
我有这段代码:
for n in (range(1,10)):
new = re.sub(r'(regex(group)regex)?regex', r'something'+str(n)+r'', old, count=1)
它抛出不匹配的组错误。但如果它不匹配,我想在那里添加空字符串而不是抛出错误。我怎样才能做到这一点?
注意:我的完整代码比这个例子复杂得多。但是,如果您找到更好的解决方案如何遍历匹配项并在其中添加数字,您可以分享。我的完整代码:
for n in (range(1,(text.count('soutez')+1))):
text = re.sub(r'(?i)(\s*\{{2}infobox medaile reprezentant(ka)?\s*\|\s*([^\}]*)\s*\}{2}\s*)?\{{2}infobox medaile soutez\s*\|\s*([^\}]*)\s*\}{2}\s*', r"\n | reprezentace"+str(n)+r" = \n | soutez"+str(n)+r" = \n | medaile"+str(n)+r" = \n", text, count=1)
根本原因
在 Python 3.5 之前,Python re.sub
中对失败捕获组的反向引用未填充空字符串。这里是Bug 1519638 description at bugs.python.org。因此,当对未参与比赛的组使用反向引用时会导致错误。
有两种方法可以解决该问题。
解决方案 1:添加空替代项以使可选组成为必需项
您可以将所有可选的捕获组(那些构造如 (\d+)?
)替换为具有空替代项(即 (\d+|)
)的强制性捕获组。
import re
old = 'regexregex'
new = re.sub(r'regex(group)?regex', r'somethingsomething', old)
print(new)
new = re.sub(r'regex(group|)regex', r'somethingsomething', old)
有效。
解决方案 2:在替换中使用 lambda 表达式并检查组是否 None
如果您在另一个可选组中有可选组,则此方法是必要的。
您可以在替换部分使用 lambda 来检查组是否已初始化,而不是 None
,使用 lambda m: m.group(n) or ''
。 在您的案例中使用此解决方案,因为您在替换模式中有两个反向引用 - #3 和 #4,但是 some matches(请参阅匹配 1 和 3)没有捕获组 3 已初始化。发生这种情况是因为整个第一部分 - (\s*\{{2}funcA(ka|)\s*\|\s*([^}]*)\s*\}{2}\s*|)
- 没有参与比赛,并且内部捕获组 3(即 ([^}]*)
)只是 即使在添加空之后也不会被填充替代.
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" = \n | funcB"+str(n)+r" = \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)
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'
我又看了一遍
请注意,不幸的是你必须处理 NULL's,
但这里是你必须遵守的规则。
以下匹配全部成功,什么都不匹配。
你必须这样做才能找出规则。
这并不像你想象的那么简单。仔细看看结果。
没有明显的固定方式 formwise 来判断您将获得 NULL 还是 EMPTY。
不过仔细一看,规则出来了,还算简单。
如果您关心 NULL,则必须遵循这些规则。
只有两条条规则:
规则 # 1 - 任何无法到达的代码 GROUP 都将导致 NULL
(?<Alt_1> # (1 start)
(?<a> a )? # (2)
(?<b> b? ) # (3)
)? # (1 end)
|
(?<Alt_2> # (4 start)
(?<c> c? ) # (5)
(?<d> d? ) # (6)
) # (4 end)
** Grp 0 - ( pos 0 , len 0 ) EMPTY
** Grp 1 [Alt_1] - ( pos 0 , len 0 ) EMPTY
** Grp 2 [a] - NULL
** Grp 3 [b] - ( pos 0 , len 0 ) EMPTY
** Grp 4 [Alt_2] - NULL
** Grp 5 [c] - NULL
规则 # 2 - 任何无法在 INSIDE 上匹配的代码组将导致 NULL
(?<A_1> # (1 start)
(?<a1> a? ) # (2)
)? # (1 end)
(?<A_2> # (3 start)
(?<a2> a )? # (4)
)? # (3 end)
(?<A_3> # (5 start)
(?<a3> a ) # (6)
)? # (5 end)
(?<A_4> # (7 start)
(?<a4> a )? # (8)
) # (7 end)
** Grp 0 - ( pos 0 , len 0 ) EMPTY
** Grp 1 [A_1] - ( pos 0 , len 0 ) EMPTY
** Grp 2 [a1] - ( pos 0 , len 0 ) EMPTY
** Grp 3 [A_2] - ( pos 0 , len 0 ) EMPTY
** Grp 4 [a2] - NULL
** Grp 5 [A_3] - NULL
** Grp 6 [a3] - NULL
** Grp 7 [A_4] - ( pos 0 , len 0 ) EMPTY
** Grp 8 [a4] - NULL
简化:
问题
- 您从 Python 2.7 正则表达式中收到错误 "sre_constants.error: unmatched group"。
- 你有任何带可选组的正则表达式模式(有或没有嵌套表达式),并试图在你的子 replacement 参数(
re.sub(pattern, *repl*, string)
或compiled.sub(*repl*, string)
)
解决方案:
对于结果,return match.group(1)
而不是 </code>(或 2、3 等)。而已;不需要 <em> 或 </em>。组结果可以 return 使用函数或 lambda 编辑。</p>
<h3>例子</h3>
<p>您正在使用 <a href="">common regex to strip C-style comments</a>. Its design <a href="https://regex101.com/r/kB5kA4/1" rel="nofollow noreferrer">uses an optional group 1</a> 传递不应删除的伪评论(如果存在)。</p>
<pre><code>pattern = r'//.*|/\*[\s\S]*?\*/|("(\.|[^"])*")'
regex = re.compile(pattern)
使用 </code> 失败并出现错误:"sre_constants.error: unmatched group":</p>
<pre><code>return regex.sub(r'', string)
使用.group(1)
成功:
return regex.sub(lambda m: m.group(1), string)
对于那些不熟悉 lambda 的人,这个解决方案等同于:
def optgroup(match):
return match.group(1)
return regex.sub(optgroup, string)
有关 为什么 </code> 由于 Bug 1519638 而失败的精彩讨论,请参阅已接受的答案。虽然已接受的答案是权威的,但它有两个缺点:1)原始问题中的示例非常复杂,以至于示例解决方案难以阅读,并且 2) 它建议 returning 一组 <strong> 或 </strong> 空字符串——这不是必需的,您可以只在每场比赛中调用 <code>.group()
。
我有这段代码:
for n in (range(1,10)):
new = re.sub(r'(regex(group)regex)?regex', r'something'+str(n)+r'', old, count=1)
它抛出不匹配的组错误。但如果它不匹配,我想在那里添加空字符串而不是抛出错误。我怎样才能做到这一点?
注意:我的完整代码比这个例子复杂得多。但是,如果您找到更好的解决方案如何遍历匹配项并在其中添加数字,您可以分享。我的完整代码:
for n in (range(1,(text.count('soutez')+1))):
text = re.sub(r'(?i)(\s*\{{2}infobox medaile reprezentant(ka)?\s*\|\s*([^\}]*)\s*\}{2}\s*)?\{{2}infobox medaile soutez\s*\|\s*([^\}]*)\s*\}{2}\s*', r"\n | reprezentace"+str(n)+r" = \n | soutez"+str(n)+r" = \n | medaile"+str(n)+r" = \n", text, count=1)
根本原因
在 Python 3.5 之前,Python re.sub
中对失败捕获组的反向引用未填充空字符串。这里是Bug 1519638 description at bugs.python.org。因此,当对未参与比赛的组使用反向引用时会导致错误。
有两种方法可以解决该问题。
解决方案 1:添加空替代项以使可选组成为必需项
您可以将所有可选的捕获组(那些构造如 (\d+)?
)替换为具有空替代项(即 (\d+|)
)的强制性捕获组。
import re
old = 'regexregex'
new = re.sub(r'regex(group)?regex', r'somethingsomething', old)
print(new)
new = re.sub(r'regex(group|)regex', r'somethingsomething', old)
有效。
解决方案 2:在替换中使用 lambda 表达式并检查组是否 None
如果您在另一个可选组中有可选组,则此方法是必要的。
您可以在替换部分使用 lambda 来检查组是否已初始化,而不是 None
,使用 lambda m: m.group(n) or ''
。 在您的案例中使用此解决方案,因为您在替换模式中有两个反向引用 - #3 和 #4,但是 some matches(请参阅匹配 1 和 3)没有捕获组 3 已初始化。发生这种情况是因为整个第一部分 - (\s*\{{2}funcA(ka|)\s*\|\s*([^}]*)\s*\}{2}\s*|)
- 没有参与比赛,并且内部捕获组 3(即 ([^}]*)
)只是 即使在添加空之后也不会被填充替代.
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" = \n | funcB"+str(n)+r" = \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)
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'
我又看了一遍
请注意,不幸的是你必须处理 NULL's,
但这里是你必须遵守的规则。
以下匹配全部成功,什么都不匹配。
你必须这样做才能找出规则。
这并不像你想象的那么简单。仔细看看结果。
没有明显的固定方式 formwise 来判断您将获得 NULL 还是 EMPTY。
不过仔细一看,规则出来了,还算简单。
如果您关心 NULL,则必须遵循这些规则。
只有两条条规则:
规则 # 1 - 任何无法到达的代码 GROUP 都将导致 NULL
(?<Alt_1> # (1 start)
(?<a> a )? # (2)
(?<b> b? ) # (3)
)? # (1 end)
|
(?<Alt_2> # (4 start)
(?<c> c? ) # (5)
(?<d> d? ) # (6)
) # (4 end)
** Grp 0 - ( pos 0 , len 0 ) EMPTY ** Grp 1 [Alt_1] - ( pos 0 , len 0 ) EMPTY ** Grp 2 [a] - NULL ** Grp 3 [b] - ( pos 0 , len 0 ) EMPTY ** Grp 4 [Alt_2] - NULL ** Grp 5 [c] - NULL
规则 # 2 - 任何无法在 INSIDE 上匹配的代码组将导致 NULL
(?<A_1> # (1 start)
(?<a1> a? ) # (2)
)? # (1 end)
(?<A_2> # (3 start)
(?<a2> a )? # (4)
)? # (3 end)
(?<A_3> # (5 start)
(?<a3> a ) # (6)
)? # (5 end)
(?<A_4> # (7 start)
(?<a4> a )? # (8)
) # (7 end)
** Grp 0 - ( pos 0 , len 0 ) EMPTY ** Grp 1 [A_1] - ( pos 0 , len 0 ) EMPTY ** Grp 2 [a1] - ( pos 0 , len 0 ) EMPTY ** Grp 3 [A_2] - ( pos 0 , len 0 ) EMPTY ** Grp 4 [a2] - NULL ** Grp 5 [A_3] - NULL ** Grp 6 [a3] - NULL ** Grp 7 [A_4] - ( pos 0 , len 0 ) EMPTY ** Grp 8 [a4] - NULL
简化:
问题
- 您从 Python 2.7 正则表达式中收到错误 "sre_constants.error: unmatched group"。
- 你有任何带可选组的正则表达式模式(有或没有嵌套表达式),并试图在你的子 replacement 参数(
re.sub(pattern, *repl*, string)
或compiled.sub(*repl*, string)
)
解决方案:
对于结果,return match.group(1)
而不是 </code>(或 2、3 等)。而已;不需要 <em> 或 </em>。组结果可以 return 使用函数或 lambda 编辑。</p>
<h3>例子</h3>
<p>您正在使用 <a href="">common regex to strip C-style comments</a>. Its design <a href="https://regex101.com/r/kB5kA4/1" rel="nofollow noreferrer">uses an optional group 1</a> 传递不应删除的伪评论(如果存在)。</p>
<pre><code>pattern = r'//.*|/\*[\s\S]*?\*/|("(\.|[^"])*")'
regex = re.compile(pattern)
使用 </code> 失败并出现错误:"sre_constants.error: unmatched group":</p>
<pre><code>return regex.sub(r'', string)
使用.group(1)
成功:
return regex.sub(lambda m: m.group(1), string)
对于那些不熟悉 lambda 的人,这个解决方案等同于:
def optgroup(match):
return match.group(1)
return regex.sub(optgroup, string)
有关 为什么 </code> 由于 Bug 1519638 而失败的精彩讨论,请参阅已接受的答案。虽然已接受的答案是权威的,但它有两个缺点:1)原始问题中的示例非常复杂,以至于示例解决方案难以阅读,并且 2) 它建议 returning 一组 <strong> 或 </strong> 空字符串——这不是必需的,您可以只在每场比赛中调用 <code>.group()
。