【问题标题】:Regex to check non-repetition of a set of characters正则表达式检查一组字符的不重复
【发布时间】:2012-04-26 11:56:43
【问题描述】:

假设我有一组字符[ABC]。我正在寻找一个正则表达式,它可以匹配除了空集之外的超集的任何排列,即

ABC ACB BAC BCA CAB CBA
AB BC AC CB CA BA
A B C

正则表达式应该(显然)匹配空字符串。

附言表达相同目标的另一种方法是“最多匹配包含集合中每个字符的任何非空字符串一次”。

更新:集合[ABC] 只是一个例子,真实的集合也可能更大。带着这个问题,我希望找到一个“通用”的解决方案,而不是为[ABC] 找到一个特定的解决方案。

【问题讨论】:

    标签: regex permutation superset


    【解决方案1】:

    我相信这可以通过正则表达式来解决。使用这个正则表达式:

    /^([ABC])(?!\1)([ABC])?(?!\1|\2)[ABC]?$/
    

    如果您需要这方面的在线演示,请告诉我。

    【讨论】:

    • @anubhava 我想(?!\1) 的意思是“向前看并确保匹配#1 不存在”?我不知道这个正则表达式功能的存在(虽然老实说我试过像(?!$1) 一样(很像替换时)。我想我今天学到了一些新东西...... :-)
    • 我还创建了一个包含大量测试字符串的演示:rubular.com/r/TpkItUFW75
    • @Dr.Kameleon: 是的(?!\1) 是一个负前瞻,这意味着A or B or C 后面不会紧跟相同的字符以避免匹配AABBCC 案例。
    【解决方案2】:

    感谢您的回答(尤其是 anubhava 和 codaddict 的),我能够找到这个解决方案,我认为它非常优雅,因为它只允许输入一次集合:

    \b(([ABC])(?!.*\2))+\b
    

    \b 需要匹配完整的单词;省略它们也会找到尊重所需属性的子词。要匹配一个完整的字符串,你显然会这样做:

    ^(([ABC])(?!.*\2))+$
    

    【讨论】:

    • 好的,我刚刚注意到了; 真的优雅地看待这个主题(尝试了类似的东西,但没能成功...... :-S)。干得好! :-)
    【解决方案3】:

    试试:

    ([ABC]?)(?!.*\1)([ABC]?)(?!.*\2)[ABC]?
    

    只是[ABC]? 重复了 3 次,并添加了对不允许重复字符的否定前瞻断言的检查。

    请注意,这只有在输入集都是唯一的情况下才有效。

    See it work

    【讨论】:

      【解决方案4】:
      "A((B?C?)|(C?B?))|B((A?C?)|(C?A?))|C((A?B?)|(B?A?))"
      

      是A|B|C,每一个都可以跟一对可选值

       A(B?C?) matches A, AB,AC and ABC
       A(C?B?) matches A, AC,AB and ACB 
      

      但不是 ACAC、AA 或 ACC。以 B 或 C 为首字符的情况是等价的。

      对于更长的字符串,这很快就会变得丑陋。更好的方法是(伪代码):

       string.sort().matches ("^A?B?C?$") && string.length > 0
      

      【讨论】:

      • 对我来说似乎是唯一正确的解决方案。在我看来,这应该是公认的解决方案。大多数其他解决方案(也是公认的解决方案)仍然允许 ABB、ACC、BAA、BBC、CCA 等。
      • @JanaWeschenfelder:谢谢,但我刚刚测试了 CAFxX 的第二种解决方案,它也对我有用,而且体积要小得多。
      • 啊,好吧...我误读了 CAFxX 的答案。我认为第二种解决方案只是第一种解决方案的替代方案。而且我只在那里测试了第一个解决方案。
      • @JanaWeschenfelder:我也成功地测试了echo ABA | grep -P '\b(([ABC])(?!.*\2))+\b',但不知道它应该在哪个程序和哪个设置下工作。 :)
      • 我知道来自 Linux 的命令 echo、pipe 和 grep,它用于在 Unix 控制台或 Linux 控制台或 Mac OS X 控制台中应用正则表达式并在那里进行测试。它不能在 Windows 下运行,除非你在那里安装 Cygwin 之类的东西。
      【解决方案5】:

      这不是正则表达式擅长的。您可能只想创建一个排列列表,然后生成所有唯一的子字符串。

      类似:

      def matches(s, characters):
          if len(s) != len(set(s)):
              return False # not unique sequence of characters
          return set(s).issubsetof(set(characters))
      

      【讨论】:

        【解决方案6】:

        试试这个:(已更新)

        A[BC](?![ABC])|B[AC](?![ABC])|C[AB](?![ABC])|[ABC](?![ABC])|(ABC|ACB|BAC|BCA|CAB|CBA)(?![ABC])
        

        演示:

        http://regexr.com?30pa6

        【讨论】:

        • 它也会匹配 AAA (从问题 可能 不可以)
        • 所有组都是可选的,所以会匹配一个空字符串
        • 另外,我以三字符组为例;实际设置可能更大。
        • @CAFxX - 如果您在问题中提及这一点可能会有所帮助
        【解决方案7】:

        这是我的版本:

        \b(?=[ABC]{1,3})([ABC]{1})(?:(?!\1)([ABC]{1})(?:(?!\1)(?!\2)[ABC]{1})?)?\b
        

        逻辑:

        • \b: 寻找单词边界
        • (?=[ABC]{1,3}): 前瞻看看是否有一个长度为 3 且值只有 A、B、C 的字符串
        • ([ABC]{1}):匹配第一个字符 然后可选
        • (?!\1)([ABC]{1}):检查下一个字符是否与先前匹配的不同 - 如果不是,则匹配它 并且可以选择
        • (?!\1)(?!\2)[ABC]{1}:检查下一个字符是否与之前匹配的字符 1 或 2 不同 - 如果不是,则匹配该字符

        我针对这个输入进行了测试,所以它看起来很可靠:

        AABCC BBCC AB BC AC CB CA BA 甲乙丙 ABC ACB BAC BCA CAB CBA AAA ABB 英国广播公司 AA


        编辑:

        正如您提到的,字符集可以更大,我会按照您问题中的 PS 建议并按照以下方式执行此操作:

        • 引入chars 数组,它将保存允许集中的每个字符(将字符串拆分为字符)

        • 获取inputStrings 的数组(在空格或其他需要的地方分割输入字符串)

        • 对于inputStrings 中的每个string {

        • 检查string.length <= inputStrings.length
        • 尝试将列表中的每个字符与当前输入匹配,并保存在matches 列表中找到的匹配数
        • 检查matches 列表是否包含任何条目,然后检查所有条目是否 == 1 或 0 }

        【讨论】:

          【解决方案8】:

          好的,我必须说,我已经对您的问题进行了很多思考,并且-因为您似乎想要一些真正通用和可定制的东西(以支持尽可能多的元素等)-我认为这就是最优解。

          从数学的角度来看,您想要的是识别所有一组元素的排列而不重复


          第一步:

          找到集合的所有排列,带有重复(并将它们存储在一个数组中)

          [ABC]([ABC]{1,2})?
          

          旁注:假设您有一个包含n 元素的集合,您所要做的就是:

          [elements]([elements]{1,n-1})?


          第二步:

          过滤所有重复元素的排列

          PHP 中的示例代码:

          <?php
          
              function strToArray($str)
              {
                  $i = 0;
          
                  while (isset($str[$i]))
                  {
                      $result[$i] = $str[$i];
                      $i++;
                  }
          
                  return $result;
              }
          
              function noDuplicates($str)
              {
                  if (array_unique(strToArray($str))==strToArray($str)) return true;
                  else return false;
              }
          
              $AAA = "AAA";
              $ABC = "ABC";
          
              if (noDuplicates($AAA)) echo "$AAA : ok"; else echo "$AAA : not ok\n";
              if (noDuplicates($ABC)) echo "$ABC : ok"; else echo "$ABC : not ok\n";
          
          ?>
          

          输出:

          AAA : not ok
          ABC : ok
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-07-06
            • 1970-01-01
            • 2012-12-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多