如何使用 '?'在python中两个匹配模式之间提取可选子字符串?

时间:2019-01-28 09:13:39

标签: python regex python-3.x substring

我是answering this questio n。考虑这个字符串

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(如果存在)。例如,在18No Allow ALL-00之间,有一个我想提取的子字符串Temp

我尝试如下使用?

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的元素):我应该只使用[^]然后使用相应的匹配模式吗?

1 个答案:

答案 0 :(得分:1)

不捕获Temp的原因是因为.*?使用了它,因此您将其设为可选,而Temp未被捕获到您的可选组中。

要解决该问题,您可以使用否定前瞻来拒绝Temp被捕获,但使用此正则表达式的其他字符除外。

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

正则表达式说明:

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

希望这可以澄清正则表达式。如果您还有其他疑问,请告诉我。

Demo

示例Python代码,

ALL-

打印

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

Demo

示例Python代码,

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

打印

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')] 的元组