首页 > 解决方案 > 匹配正则表达式排列而不重复但有一个扭曲

问题描述

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

12345

有效的排列是:

54321

55555

无效。

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

55432

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

32545

45523

但这是错误的:

55523

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

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

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

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

标签: pythonregexpermutation

解决方案


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

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。如果您还想匹配子字符串,只需从正则表达式中删除单词边界。


推荐阅读