python regex对搜索字符串的每个索引匹配多次

2024-09-22 20:24:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一种方法,使pythonre模块或更新的regex模块的finditer函数匹配特定模式的所有可能的变体,重叠或其他形式。我知道使用lookaheads可以在不消耗搜索字符串的情况下获取匹配项,但是每个索引仍然只有一个regex,在这里我可以得到多个regex。在

我使用的regex是这样的:

(?=A{2}[BA]{1,6}A{2})

所以在字符串中:

AABAABBAA

应该能够匹配:

AABAAAABAABBAAAABBAA

但目前它只会匹配最后两个。我意识到这与[BA]{1,6}的贪婪有关。有没有办法让regex匹配从最懒到最贪婪的所有模式?在


Tags: 模块方法函数字符串模式情况变体形式
3条回答

I realise it is to do with the greediness of the [BA]{1,6}. Is there a way to make the regex match everything from the laziest to the greediest possible pattern?

问题是双重的。在

1. Regex engines will only match once at a character position.
2. There is not a regex construct of between lazy and greedy  
   it's either one or the other.  

跳过问题1。目前

问题2
可能存在{1,6}1、2、3、4、5或6个匹配项
一个结构(字符)在一个给定的位置。在

要解决这个问题,您必须指定独立的{1}、{2}、{3}、{4}、{5}、{6}
作为该位置的可选替代。
显然,一个范围{1,6}是行不通的。在

范围而言,可以指定它来查找
添加lazy修饰符的最小值{1,6}?
但这只会找到它能找到的最小的数量,不能多,不能少。在

最后

问题1
当正则表达式引擎匹配时,它总是将当前位置向前推进
等于最后一次匹配的长度。
如果断言的长度为0,则会人为地增加br/> 位置向前一个字符。在


因此,考虑到这两个问题,我们可以利用这些优势/劣势来实现
想办法解决问题,还要忍受一些副作用。在

解决方法
把所有可能的选择放在一个位置作为要分析的断言。 在一个位置的每个匹配项都将包含一个包含变体的组的列表。
所以,如果你在6个可能的变量组中匹配了3个变量,那么有值的组就是变量。在

如果没有一组有值,则在该位置没有发现变体。
因为所有的断言都是可选的,所以不会发生任何变体。
为了避免在这些特定位置进行不必要的匹配,最终
条件可用于不报告这些。(即(?(1)|(?(2)|(?!)))等)。在


以您的范围为例。
我们将使用末尾的条件来验证匹配的组,
但没有它也可以做到。
_请注意,使用这个范围示例会导致相同
的重叠 最终匹配中的值。这不会在
确保唯一匹配 一个位置(下面的例子展示了如何避免这种情况)。在

^{pr2}$

输出:

 **  Grp 1 -  ( pos 0 , len 5 ) 
AABAA  
 **  Grp 2 -  ( pos 0 , len 9 ) 
AABAABBAA  

      -

 **  Grp 1 -  ( pos 3 , len 6 ) 
AABBAA  
 **  Grp 2 -  ( pos 3 , len 6 ) 
AABBAA  

相同,但没有范围问题。
在这里,我们明确定义了独特的结构。
注意每个位置的唯一值。

 # (?=(A{2}[BA]{1}A{2}))?(?=(A{2}[BA]{2}A{2}))?(?=(A{2}[BA]{3}A{2}))?(?=(A{2}[BA]{4}A{2}))?(?=(A{2}[BA]{5}A{2}))?(?=(A{2}[BA]{6}A{2}))?(?(1)|(?(2)|(?(3)|(?(4)|(?(5)|(?(6)|(?!)))))))

 (?=
      (                             # (1 start)
           A{2}
           [BA]{1} 
           A{2} 
      )                             # (1 end)
 )?
 (?=
      (                             # (2 start)
           A{2}
           [BA]{2} 
           A{2} 
      )                             # (2 end)
 )?
 (?=
      (                             # (3 start)
           A{2}
           [BA]{3} 
           A{2} 
      )                             # (3 end)
 )?
 (?=
      (                             # (4 start)
           A{2}
           [BA]{4} 
           A{2} 
      )                             # (4 end)
 )?
 (?=
      (                             # (5 start)
           A{2}
           [BA]{5} 
           A{2} 
      )                             # (5 end)
 )?
 (?=
      (                             # (6 start)
           A{2}
           [BA]{6} 
           A{2} 
      )                             # (6 end)
 )?

 (?(1)|(?(2)|(?(3)|(?(4)|(?(5)|(?(6)|(?!)))))))

输出:

 **  Grp 1 -  ( pos 0 , len 5 ) 
AABAA  
 **  Grp 2 -  NULL 
 **  Grp 3 -  NULL 
 **  Grp 4 -  NULL 
 **  Grp 5 -  ( pos 0 , len 9 ) 
AABAABBAA  
 **  Grp 6 -  NULL 

         

 **  Grp 1 -  NULL 
 **  Grp 2 -  ( pos 3 , len 6 ) 
AABBAA  
 **  Grp 3 -  NULL 
 **  Grp 4 -  NULL 
 **  Grp 5 -  NULL 
 **  Grp 6 -  NULL 

最后,您需要做的就是在每次比赛中,抓取捕捉组
并将它们放入数组中。在

此正则表达式正确匹配3个字符串:

AABAA AABAABBAA AABBAA

((^(AA){1}(BAA)$){1})|(((AA){1}(BB){1}(AA){1}$){1})

如果要用python搜索字符串“AABAABBAA”中的这些子字符串,可以使用方法“search”:

^{pr2}$

您将无法使用finditer()进行此操作,也无法使用任何常规的匹配导航方式。我管理它的唯一方法(在Java中,而不是Python中)是手动迭代源字符串的每个唯一子字符串(由起始位置和长度决定),以正常方式(而不是使用lookaround)将regex应用于每个子字符串,并在两端锚定。在

Java的Matcher类通过其region()方法提供了一种方便的方法。它允许您假设源的任何子字符串都是完整的,而不必生成新的字符串对象。而且matches()方法会自动在两端锚定匹配项,因此您根本不必修改正则表达式。在

我很确定Python的re模块不支持这样的功能,但是在另一个模块中可能有一些东西可以用来达到类似的效果(我对Python不太流利,所以这只是乐观)。我更不熟悉regex模块,但它似乎支持所有其他风格的最可爱的特性,因此值得一看。在

下面是我的Java解决方案,以防您感兴趣:

public static void printAllMatches(String text, String regex)
{
  System.out.printf("%s results:%n", text);
  Matcher m = Pattern.compile(regex).matcher(text);
  int end = text.length();
  for (int i = 0; i < end; ++i)
  {
    for (int j = i + 1; j <= end; ++j) 
    {
      m.region(i, j);

      if (m.matches()) 
      {
        for (int k = 0; k < i; k++)
        {
          System.out.print(" ");
        }
        System.out.println(m.group());
      }   
    }   
  }   
}

输出:

^{pr2}$

相关问题 更多 >