【问题标题】:How to use '?' to extract optional substring between two matching pattern in python?如何使用 '?'在python 中提取两个匹配模式之间的可选子字符串?
【发布时间】:2019-01-28 09:13:38
【问题描述】:

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

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

【问题讨论】:

    标签: python regex python-3.x substring


    【解决方案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 字符串和 * 时捕获任何内容但停止,表示捕获零个或多个字符。所以这会捕获任何不包含Temp? 的字符串,意味着尽可能少
    • (Temp)? - 可以选择捕获Temp(如果存在)
    • (?:(?!Temp).)*? - 再次捕获除Temp 之外的任何字符零次或多次,就像上面一样
    • \\t - 从字面上理解这一点
    • (.*? ALL-..) - 尽可能少地捕获任何字符,后跟空格,后跟文字 ALL-,后跟任意两个字符

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

    Demo

    示例 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-..)
    

    Demo

    示例 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的元组

    【讨论】:

    • 你的意思是拒绝Temp.*捕获?另外你能解释一下?:(?!Temp).的语法吗?
    • 好的,让我在我的帖子中添加详细说明
    • 最后一个问题:只提取那些没有Temp 的表达式 re.findall(r'from group (\d+)(?:(?!Temp).)*?[^(Temp)?](?:(?!Temp).)*?\\t(.*? ALL-..)',str1) 有效,但它是正确的吗?
    • @FrancescoBoi:如果您只想提取其中没有 Temp 的那些,则不应使用我在回答中给出的正则表达式,因为它将列出所有三个元组。使用这个正则表达式代替from group (\d+)(?:(?!Temp).)*\\t(.*? ALL-..),因为这不会列出找到Temp 的元组。让我也更新我的答案。
    • 很高兴帮助兄弟:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    相关资源
    最近更新 更多