4

假设我想确保字符串 x 等于 abcd 的任意组合(每个字符出现一次或零次-->每个字符不应重复,但组合可能以任何顺序出现)

  1. 有效前: bc .. abcd ... bcad ... b... d .. dc
  2. 无效的前。abcdd, cc, bbbb, abcde (当然)

我的努力:我尝试了各种技术:我最接近的是 x =~ ^(((a)?(b)?(c)?(d)?))$

但如果我不按照我写的顺序输入它们,这将不起作用:

  1. 适用于:ab、acd、abcd、a、d、c
  2. 不适用于:bcda、cb、da(任何不在上述顺序中的东西)

你可以在这里测试你的解决方案:http ://rubular.com/r/wCpD355bub

PS:字符可能不按字母顺序,可能是ucet

4

4 回答 4

5

如果您可以使用正则表达式以外的东西,您可以尝试:

str.chars.uniq.length == str.length && str.match(/^[a-d]+$/)

这里的一般想法是,您只需从字符串中删除任何重复的字符,如果 uniq 数组的长度不等于源字符串的长度,则字符串中有重复的字符。然后正则表达式强制执行字符集。

这可能可以改进,但它非常简单。它确实创建了几个额外的数组,因此如果需要在性能关键的位置使用它,您可能需要一种不同的方法。

如果你想坚持使用正则表达式,你可以使用:

str.match(/^[a-d]+$/) && !str.match(/([a-d]).*\1/)

这将基本上检查字符串是否只包含允许的字符,并且这些字符永远不会重复。

于 2013-06-07T22:11:51.577 回答
4

这真的不是正则表达式的本意,但如果你真的想要的话。

这是一个满足条件的正则表达式。

^([a-d])(?!(\1))([a-d])?(?!(\1|\3))([a-d])?(?!(\1|\3|\5))([a-d])?(?!(\1|\3|\5|\7))$

基本上它会遍历每个字符,创建组,然后确保该组不匹配。然后检查下一个字符,并确保该组和之前的组不匹配。

于 2013-06-07T22:20:51.127 回答
2

您可以反转它(匹配使其失败的条件)

re = /^ # start of line
(?=.*([a-d]).*\1) # match if a letter appears more than once
| # or
(?=.*[^a-d]) # match if a non abcd char appears
/x
puts 'fail' if %w{bc abcd bcad b d dc}.any?{|s| s =~ re}
puts 'fail' unless %w{abcdd cc bbbb abcde}.all?{|s| s =~ re} 
于 2013-06-07T23:44:56.070 回答
1

我认为正则表达式不太适合这个问题,所以这里有另一个非正则表达式的解决方案。它是递归的:

def match_chars_no_more_than_once(characters, string)
  return true if string.empty?
  if characters.index(string[0]) 
    match_chars_no_more_than_once(characters.sub(string[0],''), string[1..-1])
  else
    false
  end
end

%w{bc bdac hello acbbd cdda}.each do |string|
  p [string, match_chars_no_more_than_once('abcd', string)]
end

输出:

["bc", true]
["bdac", true]
["hello", false]
["acbbd", false]
["cdda", false]
于 2013-06-07T22:26:53.793 回答