没有订单的正则表达式

时间:2013-09-19 17:00:01

标签: ruby regex

假设我有一个字符列表[a,b,c],我想写一个正则表达式 如果字符列表中的所有元素至少有一次,并且字符可以按字符串中的任何顺序出现,则接受任何字符串。

接受的字符串示例

  

abc, aabbbc, bbaac, cab

不接受的字符串示例

  

aaabb, bab, caa, aacd, deeff

4 个答案:

答案 0 :(得分:3)

Sets 很多比正则表达式更适合此目的。你真正要做的是找出(a,b,c)是否是各种字符串的有效子集。以下是如何在Ruby中执行此操作的示例:

> require "set"
 => true 
> reference = Set.new("abc".split(""))
 => #<Set: {"a", "b", "c"}> 
> test1 = Set.new("aabbbc".split(""))
 => #<Set: {"a", "b", "c"}> 
> test2 = Set.new("caa".split(""))
 => #<Set: {"c", "a"}> 
> reference.subset? test1
 => true 
> reference.subset? test2
 => false 

答案 1 :(得分:2)

在阅读之前请考虑这一点:正则表达式是not always the best way来解决问题。如果你正在考虑一个正则表达式,但它并不明显或不容易继续,你可能想停下来考虑是否有一个简单的非正则表达式解决方案。

我不知道你的具体情况是什么或为什么你认为你需要正则表达式,所以我假设你已经知道上面的内容并按原样回答你的问题。


基于文档,我相信Ruby支持积极的前瞻(也称为零宽度断言)。作为一名.NET程序员,我不太清楚Ruby是否支持非固定长度的前瞻(在所有正则表达式中都没有),但如果确实如此,那么你可以很容易地应用三种不同的前瞻在表达式的开头找到您需要的每个模式或字符:

^(?=.*a)(?=.*b)(?=.*c).*

如果任何一个前瞻没有通过,这将失败。这种方法可能非常强大,因为您可以在前瞻中使用复杂的子表达式。例如:

^(?=.*a[bc]{2})(?=.*-\d)(?=.*#.{3}%).*

将测试输入包含 a ,后跟两个字符,分别是 b c - 后跟任何数字和,后跟任意三个字符,后跟,按任何特定顺序排列。因此,以下字符串将通过:

#acb%-9
#-22%abb

这种复杂的模式匹配很难简洁复制。


解决此comment

  

不存在......所以不接受abcd

您可以使用否定前瞻来确保输入中不存在其他字符而不是所需字符:

^(?=.*a)(?=.*b)(?=.*c)(?!.*[^abc]).*

(作为noted by Gene,最后的.*是没有必要的......我可能应该提到这一点。它只是在那里,以防你真的想要选择文本)

答案 2 :(得分:1)

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

答案 3 :(得分:0)

只匹配已定义字符的正则表达式可以是:

(?=[bc]*a)(?=[ac]*b)(?=[ab]*c)[abc]*