【问题标题】:Is it possible to write Python regexp with something like AND operator?是否可以使用 AND 运算符之类的东西编写 Python 正则表达式?
【发布时间】:2021-07-16 13:47:23
【问题描述】:

我找不到一种将多个正则表达式写入一个中的好方法,以便针对所有子正则表达式检查输入字符串,如下所示:

def match(input_str: str, regexp: str) -> bool:
    ...

print(match('abaaca', '.*aba.*<AND>.*aca.*'))  # True
print(match('abaca', '.*aba.*<AND>.*aca.*'))  # True, it doesn't matter that one letter a is shared
print(match('abac', '.*aba.*<AND>.*aca.*'). # False

有什么办法比解析正则表达式看看里面有没有&lt;AND&gt;,把字符串分成几个子正则表达式循环匹配?

UPD:需要明确的是,我正在寻找一种将其用作全功能运算符的方法,例如 ((a&lt;AND&gt;b)|(c&lt;AND&gt;d))&lt;AND&gt;e 将匹配所有字符串 abebaecdedce。不仅是一个&lt;AND&gt;,而是几个,夹杂着括号。

【问题讨论】:

  • 订单(aba vs aca)是否相关?例如print(match('acaba', '.*aba.*&lt;AND&gt;.*aca.*')) => 是吗?
  • 我不认为这是可能的,虽然我不清楚,所以我不会发布答案。无论如何,我认为以您想要的方式解析字符串并将其拆分为 RegExp 不是一个好主意,因为 &lt;AND&gt; 是一个完全有效的 RegExp - 所以您需要确保用户知道他们' 不输入 RegExp 并转义您用作分隔符的序列 - 或采用不易出错的路线并允许多个 RegExp 作为输入。
  • @mrxra 不,顺序不重要,re1re2和re2一样re1
  • 我在re 文档中找不到方法。我发现了一个与 many answers 相关的问题,而不是其他工具(grep、awk、sed 等)。您可以使用 Python 调用 grep/awk/sed。
  • 我的问题是你为什么要使用复杂的正则表达式而不是 Python 代码逻辑。较小和简单的正则表达式模式通常比复杂模式具有更好的性能。多个简单的正则表达式模式也将更容易编写和维护。除非单个正则表达式有明显的好处,否则我不会让它复杂化。

标签: python python-re


【解决方案1】:

正则表达式解决方案 使用正向预测组 (?=&lt;sub&gt;) 防止字符被消耗

import re

def match(input_str: str, regexp: str) -> bool:
    return re.search("".join([f"(?={sub})" for sub in re.split('<AND>', regexp)]), input_str) != None

print(match('abaaca', '.*aba.*<AND>.*aca.*'))  # True
print(match('abaca', '.*aba.*<AND>.*aca.*'))  # True, it doesn't matter that one letter a is shared
print(match('abac', '.*aba.*<AND>.*aca.*')) # False

=>

True
True
False

oneliner 相当于

def match(input_str: str, regexp: str):
    subs = re.split('<AND>', regexp)             # getting the sub patterns

    # next 3 lines create a pattern from the sub patterns
    pattern = ""
    for sub in subs:
        pattern = pattern + "(?=" + sub +  ")"   # positive lookahead syntax

    matches = re.search(pattern, input_str)
    return matches != None

对于示例模式'.*aba.*&lt;AND&gt;.*aca.*',修改后的模式是(?=.*aba.*)(?=.*aca.*)

【讨论】:

    【解决方案2】:

    您还可以实现一个函数来检查所有模式是否与字符串匹配

    import re
    
    def matchall(patterns, string):
        return all([re.search(pattern, string) for pattern in patterns])
    
    print(matchall([".*aba.*", ".*aca.*"], "abaaca"))  # True
    

    【讨论】:

    • 请注意,“acaaba”也将返回 True。此解决方案在集合中用作联合,并且不保留顺序。
    【解决方案3】:

    共享一个字母a并不重要

    不,你不能只用一个正则表达式来做到这一点。 From the documentation for match():

    如果字符串开头的零个或多个字符与正则表达式模式匹配,则返回相应的匹配对象。

    换句话说,整个正则表达式必须匹配字符串的开头。即使您更改为re.search(),您仍然必须匹配输入字符串中某处的整个正则表达式。 re.findall() 会搜索不重叠的匹配项。

    【讨论】:

    • ...我猜match 是一种自定义方法,而不是标准库中的方法....虽然不确定....@sanyassh?
    • @mrxra 啊...我错过了 OP 代码中的 def
    • @mrxra 是正确的 - 问题不在于 re.match 完全正确,而是关于使用任何 re.match 的自定义函数。功能。
    【解决方案4】:

    基本上,正则表达式检查aba.*acaaca.*aba 的字符串。向后看是必要的,因为可能有一个 a 是两个子模式的一部分

    import re
    
    regex = r"aba.*(?<=a)ca|aca.*(?<=a)ba"
    for s in ['abaaca', 'abaca', 'abac', 'aaacacabbaba', 'abababaca', 'abbbacaaaba']:
        print(s, '=>', bool(re.search(regex, s)))
    

    输出:

    abaaca => True
    abaca => True
    abac => False
    aaacacabbaba => True
    abababaca => True
    abbbacaaaba => True
    

    【讨论】:

      【解决方案5】:

      在 Artyom Vancyan answer 的基础上,我将遍历已编译的正则表达式列表,因为如果多次调用该函数,它将为您带来巨大的性能提升。

      import re
      expressions = [re.compile(r'abaaca'), re.compile(r'abaca'), re.compile(r'abac')]
      def match_expressions(expressions, string_to_match):
          return all([expression.search(string_to_match) for expression in expressions])
      

      【讨论】:

        【解决方案6】:
        import re
        
        
        def match(input_str: str, regexp: str) -> bool:
            pattern = "".join(
                [f"(?={condition})" for condition in regexp.split("<AND>")]
            )
        
            return bool(re.findall(pattern, input_str))
        
        print(match("abaaca", ".*aba.*<AND>.*aca.*"))  # True
        print(match("abaca", ".*aba.*<AND>.*aca.*"))  # True, it doesn't matter that one letter a is shared
        print(match("abac", ".*aba.*<AND>.*aca.*"))  # False
        

        【讨论】:

          【解决方案7】:

          以下模式几乎匹配所有。

          # Regex If order is important, i.e. should start with aba
          pattern = r'.*ab(a.*a|a)ca.*' 
          # Regex If order is not important, i.e. It can start with aba | aca
          pattern = r'.*a(b(a.*a|a)c|c(a.*a|a)b)a.*'
          # OUTPUTS
          #False inputs
          string = ['abac','aba_ca','acab','_ab_ca_','acab','aca ba','_ababa_test_aba_']
          print(re.search(pattern, string[0])) # O/P False
          # True inputs
          string = ["abaca",'acaba','aca_test_aba','_aba_test_aca_','acaaba','abaaca']
          print(re.search(pattern, string[0])) # O/P True
          

          【讨论】:

            【解决方案8】:

            不,python 正则表达式语法中没有这样的运算符。在这种情况下,您可以使用类似

            .*ab(a.*)ca.*
            

            【讨论】:

            • 这将匹配aba_ca,注意没有aca
            猜你喜欢
            • 2010-10-02
            • 2010-10-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多