假设我有一组字符[ABC]
。我正在寻找一个正则表达式,它可以匹配除了空集之外的超集的任何排列,即
ABC ACB BAC BCA CAB CBA
AB BC AC CB CA BA
A B C
正则表达式应该(显然)不匹配空字符串。
ps 表达相同目标的另一种方法是“最多匹配包含集合中每个字符的任何非空字符串一次”。
更新:集合[ABC]
只是一个例子,真实的集合也可能更大。带着这个问题,我希望找到一个“通用”的解决方案,而不是针对[ABC]
.
假设我有一组字符[ABC]
。我正在寻找一个正则表达式,它可以匹配除了空集之外的超集的任何排列,即
ABC ACB BAC BCA CAB CBA
AB BC AC CB CA BA
A B C
正则表达式应该(显然)不匹配空字符串。
ps 表达相同目标的另一种方法是“最多匹配包含集合中每个字符的任何非空字符串一次”。
更新:集合[ABC]
只是一个例子,真实的集合也可能更大。带着这个问题,我希望找到一个“通用”的解决方案,而不是针对[ABC]
.
我相信这可以通过正则表达式来解决。使用这个正则表达式:
/^([ABC])(?!\1)([ABC])?(?!\1|\2)[ABC]?$/
如果您需要在线演示,请告诉我。
感谢您的回答(尤其是 anubhava 和 codaddict 的),我能够找到这个解决方案,我认为它非常优雅,因为它只允许输入一次集合:
\b(([ABC])(?!.*\2))+\b
\b
需要匹配完整的单词;省略它们也会找到尊重所需属性的子词。要匹配一个完整的字符串,你显然会这样做:
^(([ABC])(?!.*\2))+$
这不是正则表达式擅长的。您可能只想创建一个排列列表,然后生成所有唯一的子字符串。
就像是:
def matches(s, characters):
if len(s) != len(set(s)):
return False # not unique sequence of characters
return set(s).issubsetof(set(characters))
尝试:
([ABC]?)(?!.*\1)([ABC]?)(?!.*\2)[ABC]?
它只是[ABC]?
重复了 3 次,并添加了对不允许重复字符的否定前瞻断言的检查。
请注意,这仅在输入集都是唯一的情况下才有效。
"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
好的,我必须说我已经考虑了很多你的问题 - 因为你似乎想要一些真正通用和可定制的东西(支持尽可能多的元素等) - 这是我认为最优化的解决方案。
从数学的角度来看,您想要的是识别一组元素的所有排列而不重复。
找到集合的所有排列,重复(并将它们存储在一个数组中)
[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
这是我的版本:
\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 ABC ACB BAC BCA CAB CBA AAA ABB AAA BBC AA
编辑:
正如您提到的,字符集可以更大,我会按照您问题中的 PS 建议并按照以下方式执行此操作:
引入chars
数组,它将保存允许集中的每个字符(将字符串拆分为字符)
得到一个数组inputStrings
(在空格或其他任何需要的地方分割输入字符串)
对于
{string
中的每个inputStrings
string.length <= inputStrings.length
matches
列表中找到的匹配数matches
列表是否包含任何条目,然后检查所有条目是否 == 1 或 0 }试试这个:(更新)
A[BC](?![ABC])|B[AC](?![ABC])|C[AB](?![ABC])|[ABC](?![ABC])|(ABC|ACB|BAC|BCA|CAB|CBA)(?![ABC])
演示: