首页 > 解决方案 > 如何使用 '?' 在python 中提取两个匹配模式之间的可选子字符串?

问题描述

我正在回答这个问题。考虑这个字符串

str1 = '{"show permission allowed to 16": "show permission to 16\\nSchool permissions from group 17:student to group 16:teacher:\\n\\tAllow ALL-00\\nSchool permissions from group 18:library to group 16(Temp):teacher:\\n\\tNo Allow ALL-00\\nSchool permissions from group 20:Gym to group 16:teacher:\\n\\tCheck ALL-00\\nRTYAHY: FALSE\\nRTYAHY: FALSE\\n\\n#"}'

并假设我想在每个子字符串from group\\t具有最小匹配字符串之后的子字符串之后提取数字。

我用下面的正则表达式做到了这一点

import re
res = re.findall(r'from group (\d+).*?\\t(.*? ALL-..)', str1)

输出是:

[('17', 'Allow ALL-00'), ('18', 'No Allow ALL-00'), ('20', 'Check ALL-00')]

现在在我提取的每个子字符串之间(数字和 之后的子字符串\t)可能有一个可选的子字符串,它的值是Temp我想要提取的(如果存在)。例如,在18和之间No Allow ALL-00Temp我想提取的子字符串。

我尝试使用?如下:

res = re.findall(r'from group (\d+).*?(Temp)?.*?\\t(.*? ALL-..)', str1)

但结果元组的相应第二个元素始终为空:

[('17', '', 'Allow ALL-00'), ('18', '', 'No Allow ALL-00'), ('20', '', 'Check ALL-00')]

虽然我期待类似的东西:

[('17', '', 'Allow ALL-00'), ('18', 'Temp', 'No Allow ALL-00'), ('20', '', 'Check ALL-00')]

在这种情况下如何提取子字符串?我在做什么错误?

还有一个问题:假设我希望我的结果列表没有这个元素(包含 的那个Temp):我应该只使用[^]然后使用相应的匹配模式吗?

标签: pythonregexpython-3.xsubstring

解决方案


它未捕获的原因Temp是因为您已将其设为可选,因为它.*?会消耗它,并且Temp不会在您的可选组中捕获。

为了解决这个问题,您可以使用否定前瞻来拒绝Temp被捕获,但使用此正则表达式的任何其他字符除外,

from group (\d+)(?:(?!Temp).)*?(Temp)?(?:(?!Temp).)*?\\t(.*? ALL-..)
                   ^^^^^^^^^ This rejects Temp getting captured except any other character

正则表达式解释:

  • from group- 此文本的字面匹配
  • (?:(?!Temp).)*?-?:表示它是一个非捕获组,默认情况下是一个捕获组,这意味着捕获任何内容,但在您看到Temp字符串时会停止,这*意味着捕获零个或多个字符。所以这会捕获任何不包含Temp并且?意味着尽可能少的字符串
  • (Temp)?- 可选择捕获(Temp如果存在)
  • (?:(?!Temp).)*?- 再次捕获任何字符零次或多次,除了Temp上面一样
  • \\t- 从字面上捕捉这一点
  • (.*? ALL-..)- 尽可能少地捕获任何字符,后跟空格,后跟文字ALL-,后跟任意两个字符

希望这可以澄清正则表达式。如果您有任何进一步的疑问,请告诉我。

演示

示例 Python 代码,

import re

s = '{"show permission allowed to 16": "show permission to 16\\nSchool permissions from group 17:student to group 16:teacher:\\n\\tAllow ALL-00\\nSchool permissions from group 18:library to group 16(Temp):teacher:\\n\\tNo Allow ALL-00\\nSchool permissions from group 20:Gym to group 16:teacher:\\n\\tCheck ALL-00\\nRTYAHY: FALSE\\nRTYAHY: FALSE\\n\\n#"}'

arr = re.findall(r'from group (\d+)(?:(?!Temp).)*?(Temp)?(?:(?!Temp).)*?\\t(.*? ALL-..)',s)
print(arr)

印刷,

[('17', '', 'Allow ALL-00'), ('18', 'Temp', 'No Allow ALL-00'), ('20', '', 'Check ALL-00')]

编辑:仅列出不包含的元组Temp

您将需要使用此正则表达式来避免匹配匹配中包含Temp字符串的子字符串,

from group (\d+)(?:(?!Temp).)*\\t(.*? ALL-..)

演示

示例 Python 代码,

import re

str1 = '{"show permission allowed to 16": "show permission to 16\\nSchool permissions from group 17:student to group 16:teacher:\\n\\tAllow ALL-00\\nSchool permissions from group 18:library to group 16(Temp):teacher:\\n\\tNo Allow ALL-00\\nSchool permissions from group 20:Gym to group 16:teacher:\\n\\tCheck ALL-00\\nRTYAHY: FALSE\\nRTYAHY: FALSE\\n\\n#"}'

arr = re.findall(r'from group (\d+)(?:(?!Temp).)*\\t(.*? ALL-..)',str1)
print(arr)

印刷,

[('17', 'Allow ALL-00'), ('20', 'Check ALL-00')]

其中不包含具有的元组Temp


推荐阅读