【问题标题】:Match Regex permuations without repeating but with a twist匹配正则表达式排列而不重复但有一个扭曲
【发布时间】:2021-04-11 01:14:25
【问题描述】:

似乎我找不到解决这个问题的方法,这可能是一个简单的问题:我希望能够用一个简单的正则表达式匹配 5 个指定数字的所有可能排列,而无需重复,必须使用所有数字。所以,对于这个序列:

12345

有效的排列是:

54321

但是

55555

无效。

但是,如果提供的数字有一次或多次相同的数字,则只有在这种情况下,接受的排列才会有那些重复的数字,但每个数字只能使用一次。例如,如果提供的数字是:

55432

我们看到 5 提供了 2 次,因此它在每个排列中也必须出现两次,并且一些接受的答案是:

32545

45523

但这是错误的:

55523

(并非所有原始数字都被使用,并且 5 重复了两次以上)

我非常接近解决这个问题:

(?:([43210])(?!.*\1)){5}

但不幸的是,当提供多个相同的数字时它不起作用(如 43211)。

【问题讨论】:

    标签: python regex permutation


    【解决方案1】:

    解决这个问题的一种方法是从搜索数字中创建一个字符类,并构建一个正则表达式来搜索该类中与搜索字符串中一样多的数字。然后,您可以根据排序匹配字符串与排序搜索字符串相同来过滤正则表达式结果。例如:

    import re
    
    def find_perms(search, text):
        search = sorted(search)
        regex = re.compile(rf'\b[{"".join(search)}]{{{len(search)}}}\b')
        matches = [m for m in regex.findall(text) if sorted(m) == search]
        return matches
    
    print(find_perms('54321', '12345 54321 55432'))
    print(find_perms('23455', '12345 54321 55432'))
    print(find_perms('24455', '12345 54321 55432'))
    

    输出:

    ['12345', '54321']
    ['55432']
    []
    

    请注意,我在正则表达式中包含了单词边界 (\b),因此(例如)12345 不会匹配 654321。如果您也想匹配子字符串,只需从正则表达式中删除单词边界即可。

    【讨论】:

      【解决方案2】:

      对此的数学术语是多集。在 Python 中,这是由 Counter 数据类型处理的。例如,

      from collections import Counter
      target = '55432'
      candidate = '32545'
      Counter(candidate) == Counter(target)
      

      如果你想生成所有的多集,这里有一个问题:How to generate all the permutations of a multiset?

      【讨论】:

      • 出于好奇,我定时比较两个计数器并比较两个排序列表(其中输入是 5 个字符串),比较排序列表的速度大约快 6 倍。即使对于 10 个字符的字符串,排序也快 4 倍。 rextester.com/IBG64719
      猜你喜欢
      • 2011-03-07
      • 1970-01-01
      • 1970-01-01
      • 2014-09-05
      • 2022-12-11
      • 2015-01-27
      • 1970-01-01
      • 1970-01-01
      • 2014-09-26
      相关资源
      最近更新 更多