4

文字列 x が abcd の任意の組み合わせと等しいことを確認したいとします (各文字は 1 回または 0 回表示されます。各文字は繰り返されるべきではありませんが、組み合わせは任意の順序で表示されます)。

  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 に答える