假设我有一个字符列表 [a,b,c] 并且我想编写一个正则表达式,以便任何字符串都被接受,如果它具有字符列表中的所有元素至少一次并且字符可以以任何顺序出现在字符串中。
接受的字符串示例
abc, aabbbc, bbaac, cab
不接受的字符串示例
aaabb, bab, caa, aacd, deeff
在继续阅读之前考虑这一点:正则表达式并不总是解决问题的最佳方法。如果您正在考虑使用正则表达式,但它并不明显或不容易进行,您可能需要停下来考虑是否有方便的非正则表达式解决方案。
我不知道你的具体情况是什么,或者你为什么认为你需要正则表达式,所以我假设你已经知道上述内容并按原样回答你的问题。
根据文档,我相信 Ruby 支持正向前瞻(也称为零宽度断言)。作为主要的 .NET 程序员,我对 Ruby 的了解还不够充分,无法说出它是否支持非固定长度的前瞻(并非在所有正则表达式中都可以找到),但如果支持,那么您可以轻松应用三种不同的前瞻在表达式的开头找到您需要的每个模式或字符:
^(?=.*a)(?=.*b)(?=.*c).*
如果任何一个前瞻没有通过,这将失败。这种方法可能非常强大,因为您可以在前瞻中包含复杂的子表达式。例如:
^(?=.*a[bc]{2})(?=.*-\d)(?=.*#.{3}%).*
将测试输入是否包含a 后跟a两个字符,每个字符是 ab或 a c, a-后跟任何数字, a#后跟任意三个字符,后跟 a %,以任何特定顺序。所以下面的字符串会通过:
#acb%-9
#-22%abb
这种复杂的模式匹配很难简洁地复制。
要解决此评论:
不,不可能……所以不接受 abcd
您可以使用负前瞻来确保输入中不存在所需字符以外的字符:
^(?=.*a)(?=.*b)(?=.*c)(?!.*[^abc]).*
(正如Gene所指出的,.*
最后的不是必要的......我可能应该提到这一点。它就在那里,以防你真的想选择文本)
集合比正则表达式更适合这个目的。您真正想做的是找出(a, b, c)是否是您的各种字符串的有效子集。以下是如何在 Ruby 中执行此操作的示例:
> 需要“设置” => 真 > 参考 = Set.new("abc".split("")) => #<设置:{“a”、“b”、“c”}> > test1 = Set.new("aabbbc".split("")) => #<设置:{“a”、“b”、“c”}> > test2 = Set.new("caa".split("")) => #<设置:{"c", "a"}> > 参考子集?测试1 => 真 > 参考子集?测试2 => 假的
def acceptable? s
s =~ /(?=.*a)(?=.*b)(?=.*c)/
end
acceptable? 'abc' # => 0
acceptable? 'aabbbc' # => 0
acceptable? 'bbaac' # => 0
acceptable? 'cab' # => 0
acceptable? 'aaabb' # => nil
acceptable? 'bab' # => nil
acceptable? 'caa' # => nil
acceptable? 'aacd' # => nil
acceptable? 'deeff' # => nil
acceptable? 'abcd' # => 0
仅匹配已定义字符的正则表达式可能是:
(?=[bc]*a)(?=[ac]*b)(?=[ab]*c)[abc]*