【问题标题】:Generate a regex to find sub strings with certain number of occurrences of certain characters生成一个正则表达式来查找特定字符出现一定次数的子字符串
【发布时间】:2014-04-02 20:58:21
【问题描述】:

假设我有一个字符串"IICCIICCIICBIICCIICDII"。该字符串的模式为II[CBD][CBD]II[CBD][CBD]II..。这是一个重复的模式。现在我正在尝试找到满足以下条件的所有 重叠 子字符串:

  1. 子字符串不以字母 I 开头或结尾。建议的解决方案:(?<=[CBD]), (?=[CBD])
  2. 子字符串至少(但尽可能少)包含一定数量的字母 C、B 和 D。这些字母可以以任何排列形式存在,并且可以有不同的出现次数。建议的解决方案:类似于[C]{m, n}?
  3. 这些预定义的数字是可变的,因此我可以根据这些变量的需求变化动态生成正则表达式。
  4. 字母 I 出现的顺序和次数无关紧要
  5. 添加到条件 1:子字符串的开头/结尾不能出现两次 [CBD](例如,CCIIB 或 BIICC 是无效匹配)(对此感到抱歉)

例如,对于至少有 2 个 C 的模式:CIIC(其中三个)、2 个 C 和 1 个 B:CIICBIIC、BIICCIIC

我认为我的问题与其中一个答案中引用的问题不同。我看过那个问题(标题为“最短重复子串”)。我的问题在重复模式需要出现一定数量的某些字符的意义上有所不同。引用的问题只是找到最短的重复模式。不过这个问题很有帮助。

如果问题清楚且不重复,请告诉我。 谢谢。

【问题讨论】:

  • @aliteralmind:虽然链接的问题很相似,但这个 Q 是针对 Python,而不是针对 C# 或 Java。对于 Python,this Q 可能会有所帮助。用户似乎熟悉正则表达式,但不熟悉 Python。这是正确的吗?
  • 这个at least 2 Cs: CIIC (three of them), 2 Cs and 1 B: CIICBIIC, BIICCIIC不太清楚。
  • 好的,所以我为这个非常困难的问题添加了答案。但是,重复,真的吗?重复的参考链接here(从上面)接受这个(?<=n)n 的答案。这真的回答了这个问题吗?任何独立的前瞻都是重叠的。不妨将所有正则表达式问题标记为重复,因为这就是这个问题对那个问题的水平。太糟糕了,因为这个问题有很多永远不会思考的领域。
  • 感谢@sln 认识到这不是一个重复的问题。

标签: python regex


【解决方案1】:

最终分析

介绍您最新的 cmets。
正如怀疑的那样,这不能用正则表达式来完成,除非
它可以做计数。具体来说,计数具有重置计数器的能力
回溯的时候。

只有一个引擎可以做到这一点,那就是 Perl,不幸的是,
使用 Python 完成这项任务是不可能的。

我在下面添加 Perl 正则表达式来做到这一点。仅添加它以可视化
如果您想在不使用正则表达式的情况下完成相同的任务。
这当然可以做到。

抱歉,对您没有什么帮助。 - sln

 # (?{ $vb=0; $vc=0; $vd=0; })(?=(?![BCD]{2})(?![I])((?:(?:[B][I]*?)(?{ local $vb = $vb+1 })|(?:[C][I]*?)(?{ local $vc = $vc+1 })|(?:[D][I]*?)(?{ local $vd = $vd+1 }))+?)(?(?{$vb >= 2 && $vc >= 5 && $vd >= 2})(?{ $VB=$vb; $VC=$vc; $VD=$vd; })|(?!))(?<![I])(?<![BCD]{2}))
 #

 (?{ $vb=0; $vc=0; $vd=0; })         # Initialize local counters to zero
 (?=
      (?! [BCD]{2} )                      # App Condition 5a, not start with 2 occurances of BCD
      (?! [I] )                           # App Condition 1a, not start with I
      (                                   # (1 start)
           (?:                                 # Cluster group start (App Conditions 2-4)
                (?: [B] [I]*? )                     # 'B'
                (?{ local $vb = $vb+1 })            # Increment local 'B' counter
             |  
                (?: [C] [I]*? )                     # 'C'
                (?{ local $vc = $vc+1 })            # Increment local 'C' counter
             |  
                (?: [D] [I]*? )                     # 'D'
                (?{ local $vd = $vd+1 })            # Increment local 'D' counter
           )+?                                 # Cluster group end, do the minimum
                                               # to satisfy conditions
      )                                   # (1 end)

      (?(?{
           # Code conditional - the local counters
           # must be greater than or equal to these values
           $vb >= 2 && $vc >= 5 && $vd >= 2
        })
           # Yes condition, copy local counters to global vars.
           (?{ $VB=$vb; $VC=$vc; $VD=$vd; })
        |  
           # No condition, fail the expression here
           # force engine to backtrack (and reset local counters) 
           (?!)
      )
      (?<! [I] )                          # App Condition 1b, not end with I
      (?<! [BCD]{2} )                     # App Condition 5b, not end with 2 occurances of BCD
 )

Perl 测试用例

 $str = "IICCIICBIICCIIDCIICCIICDIICCIIBCIICCIICBIICCIIDCIICCIICCIICCII";
 print  "\n";
 print  "01234567890123456789012345678901234567890123456789012345678901\n";
 print  "          1         2         3         4         5         6\n";
 print  $str,"\n-------------------------------------------------------\n";

 FindOverlaps(2,5,2);
 FindOverlaps(1,2,0);
 FindOverlaps(1,1,0);
 FindOverlaps(1,1,1);
 FindOverlaps(0,1,1);
 FindOverlaps(1,0,1);

 sub FindOverlaps
 {
     ($MinB, $MinC, $MinD) = @_;

     print "\nB=$MinB, C=$MinC, D=$MinD\n";

     while ( $str =~ /

          (?{ $vb=0; $vc=0; $vd=0; })         # Initialize local counters to zero
          (?=
               (?! [BCD]{2} )                      # App Condition 5a, not start with 2 occurances of BCD
               (?! [I] )                           # App Condition 1a, not start with I
               (                                   # (1 start)
                    (?:                                 # Cluster group start (App Conditions 2-4)
                         (?: [B] [I]*? )                     # 'B'
                         (?{ local $vb = $vb+1 })            # Increment local 'B' counter
                      |  
                         (?: [C] [I]*? )                     # 'C'
                         (?{ local $vc = $vc+1 })            # Increment local 'C' counter
                      |  
                         (?: [D] [I]*? )                     # 'D'
                         (?{ local $vd = $vd+1 })            # Increment local 'D' counter
                    )+?                                 # Cluster group end, do the minimum
                                                        # to satisfy conditions
               )                                   # (1 end)

               (?(?{
                    # Code conditional - the local counters
                    # must be greater than or equal to these values
                    $vb >= $MinB && $vc >= $MinC && $vd >= $MinD
                 })
                    # Yes condition, copy local counters to global vars.
                    (?{ $VB=$vb; $VC=$vc; $VD=$vd; })
                 |  
                    # No condition, fail the expression here
                    # force engine to backtrack (and reset local counters) 
                    (?!)
               )
               (?<! [I] )                          # App Condition 1b, not end with I
               (?<! [BCD]{2} )                     # App Condition 5b, not end with 2 occurances of BCD
          )
     /xg )
     {
        print sprintf("found:   %-10s %-30s  offset = %s\n", "\($VB,$VC,$VD\)", $1, @-[0]);
     }
 }

输出>>

 01234567890123456789012345678901234567890123456789012345678901
           1         2         3         4         5         6
 IICCIICBIICCIIDCIICCIICDIICCIIBCIICCIICBIICCIIDCIICCIICCIICCII
 -------------------------------------------------------

 B=2, C=5, D=2
 found:   (2,10,2)   CIICBIICCIIDCIICCIICDIICCIIB    offset = 3
 found:   (2,8,2)    BIICCIIDCIICCIICDIICCIIB        offset = 7
 found:   (2,12,2)   CIIDCIICCIICDIICCIIBCIICCIICBIIC  offset = 11
 found:   (2,12,2)   CIICCIICDIICCIIBCIICCIICBIICCIID  offset = 15
 found:   (2,10,2)   CIICDIICCIIBCIICCIICBIICCIID    offset = 19
 found:   (2,8,2)    DIICCIIBCIICCIICBIICCIID        offset = 23

 B=1, C=2, D=0
 found:   (1,3,0)    CIICBIIC                        offset = 3
 found:   (1,2,1)    BIICCIID                        offset = 7
 found:   (1,7,2)    CIIDCIICCIICDIICCIIB            offset = 11
 found:   (1,6,1)    CIICCIICDIICCIIB                offset = 15
 found:   (1,4,1)    CIICDIICCIIB                    offset = 19
 found:   (1,2,1)    DIICCIIB                        offset = 23
 found:   (1,3,0)    CIIBCIIC                        offset = 27
 found:   (1,5,0)    CIICCIICBIIC                    offset = 31
 found:   (1,3,0)    CIICBIIC                        offset = 35
 found:   (1,2,1)    BIICCIID                        offset = 39

 B=1, C=1, D=0
 found:   (1,3,0)    CIICBIIC                        offset = 3
 found:   (1,1,0)    BIIC                            offset = 7
 found:   (1,7,2)    CIIDCIICCIICDIICCIIB            offset = 11
 found:   (1,6,1)    CIICCIICDIICCIIB                offset = 15
 found:   (1,4,1)    CIICDIICCIIB                    offset = 19
 found:   (1,2,1)    DIICCIIB                        offset = 23
 found:   (1,1,0)    CIIB                            offset = 27
 found:   (1,5,0)    CIICCIICBIIC                    offset = 31
 found:   (1,3,0)    CIICBIIC                        offset = 35
 found:   (1,1,0)    BIIC                            offset = 39

 B=1, C=1, D=1
 found:   (1,4,1)    CIICBIICCIID                    offset = 3
 found:   (1,2,1)    BIICCIID                        offset = 7
 found:   (1,7,2)    CIIDCIICCIICDIICCIIB            offset = 11
 found:   (1,6,1)    CIICCIICDIICCIIB                offset = 15
 found:   (1,4,1)    CIICDIICCIIB                    offset = 19
 found:   (1,2,1)    DIICCIIB                        offset = 23
 found:   (2,7,1)    CIIBCIICCIICBIICCIID            offset = 27
 found:   (1,6,1)    CIICCIICBIICCIID                offset = 31
 found:   (1,4,1)    CIICBIICCIID                    offset = 35
 found:   (1,2,1)    BIICCIID                        offset = 39

 B=0, C=1, D=1
 found:   (1,4,1)    CIICBIICCIID                    offset = 3
 found:   (1,2,1)    BIICCIID                        offset = 7
 found:   (0,1,1)    CIID                            offset = 11
 found:   (0,5,1)    CIICCIICDIIC                    offset = 15
 found:   (0,3,1)    CIICDIIC                        offset = 19
 found:   (0,1,1)    DIIC                            offset = 23
 found:   (2,7,1)    CIIBCIICCIICBIICCIID            offset = 27
 found:   (1,6,1)    CIICCIICBIICCIID                offset = 31
 found:   (1,4,1)    CIICBIICCIID                    offset = 35
 found:   (1,2,1)    BIICCIID                        offset = 39
 found:   (0,1,1)    CIID                            offset = 43

 B=1, C=0, D=1
 found:   (1,4,1)    CIICBIICCIID                    offset = 3
 found:   (1,2,1)    BIICCIID                        offset = 7
 found:   (1,7,2)    CIIDCIICCIICDIICCIIB            offset = 11
 found:   (1,6,1)    CIICCIICDIICCIIB                offset = 15
 found:   (1,4,1)    CIICDIICCIIB                    offset = 19
 found:   (1,2,1)    DIICCIIB                        offset = 23
 found:   (2,7,1)    CIIBCIICCIICBIICCIID            offset = 27
 found:   (1,6,1)    CIICCIICBIICCIID                offset = 31
 found:   (1,4,1)    CIICBIICCIID                    offset = 35
 found:   (1,2,1)    BIICCIID                        offset = 39

(旧)

我认为这是你可以用正则表达式做的最好的事情

编辑 - 针对新条件 5 进行了修改。

 #  String:
 #  (?=(?![BCD]{2})(?![I])((?:[B][IDC]*?){1}(?:[C][IDB]*?){2}(?:[D][IBC]*?){0}|(?:[C][IDB]*?){2}(?:[D][IBC]*?){0}(?:[B][IDC]*?){1}|(?:[D][IBC]*?){0}(?:[B][IDC]*?){1}(?:[C][IDB]*?){2}|(?:[C][IDB]*?){2}(?:[B][IDC]*?){1}(?:[D][IBC]*?){0})(?<![I])(?<![BCD]{2}))

 # Example: Finds 1-B, 2-C's     
 (?=
      (?! [BCD]{2} )              # Condition 5a, not start with 2 occurances of BCD
      (?! [I] )                   # Condition 1a, not start with I (not really necessary here)

      (                           # (1 start), Conditions 2-4
           (?: [B] [IDC]*? ){1}
           (?: [C] [IDB]*? ){2}
           (?: [D] [IBC]*? ){0}
        |  
           (?: [C] [IDB]*? ){2}
           (?: [D] [IBC]*? ){0}
           (?: [B] [IDC]*? ){1}
        |  
           (?: [D] [IBC]*? ){0}
           (?: [B] [IDC]*? ){1}
           (?: [C] [IDB]*? ){2}
        |  
           (?: [C] [IDB]*? ){2}
           (?: [B] [IDC]*? ){1}
           (?: [D] [IBC]*? ){0}
      )                           # (1 end)

      (?<! [I] )                  # Condition 1b, not end with I
      (?<! [BCD]{2} )             # Condition 5b, not end with 2 occurances of BCD
 )

Perl 测试用例

  $str = "IICCIICCIICBIICCIICDIIDIICCIIB";

  print  "\n";
  print  "012345678911234567892123456789\n";
  print  "          +         +         \n";
  print  $str,"\n------------------------------\n";

  ($B,$C,$D) = (1,2,0);
  FindOverlaps();

  ($B,$C,$D) = (1,1,0);
  FindOverlaps();

  ($B,$C,$D) = (1,1,1);
  FindOverlaps();

  ($B,$C,$D) = (0,1,1);
  FindOverlaps();

  ($B,$C,$D) = (1,0,1);
  FindOverlaps();

  sub FindOverlaps
  {
      print "\nB=$B, C=$C, D=$D\n";

      while ( $str =~ /(?=(?![BCD]{2})(?![I])((?:[B][IDC]*?){$B}(?:[C][IDB]*?){$C}(?:[D][IBC]*?){$D}|(?:[C][IDB]*?){$C}(?:[D][IBC]*?){$D}(?:[B][IDC]*?){$B}|(?:[D][IBC]*?){$D}(?:[B][IDC]*?){$B}(?:[C][IDB]*?){$C}|(?:[C][IDB]*?){$C}(?:[B][IDC]*?){$B}(?:[D][IBC]*?){$D})(?<![I])(?<![BCD]{2}))/g )
      {
          print "found:  '$1' \t offset = @-[0]\n";
      }
  }

输出>>

 012345678911234567892123456789
           +         +
 IICCIICCIICBIICCIICDIIDIICCIIB
 ------------------------------

 B=1, C=2, D=0
 found:  'CIICBIIC'       offset = 7
 found:  'BIICCIIC'       offset = 11

 B=1, C=1, D=0
 found:  'BIIC'   offset = 11
 found:  'CIIB'   offset = 26

 B=1, C=1, D=1
 found:  'BIICCIICDIID'   offset = 11

 B=0, C=1, D=1
 found:  'DIIC'   offset = 22

 B=1, C=0, D=1
 found:  'BIICCIICDIID'   offset = 11
 found:  'DIICCIIB'       offset = 22

【讨论】:

  • 感谢您的回复。我正在寻找您提供的内容。虽然,我应该更清楚。还有另一个条件(请参阅已编辑问题中的条件 5,对此感到抱歉)。此条件不允许匹配,例如 BC、CB、BIICC(在匹配结束或开始时有两个连续 [CBD] 的任何内容。
  • @user3491040 - 欢迎您!添加条件 5,一个简单的修复。
  • 这太棒了。谢谢!!
  • @user3491040:点击绿色的大勾号,考虑投票并接受这个答案。 @sln:我投票决定重新开放。
  • 我想我不能投票,因为我是堆栈溢出的新手,但我确实接受了你的回答。
猜你喜欢
  • 1970-01-01
  • 2014-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多