4

順序に関係なく、文字のセットに一致する正規表現を作成しようとしています。例えば:

str = "act" 
str.scan(/Insert expression here/)

一致します:

cat
act
tca
atc
tac
cta

caただし、、、またはとは一致しませaccata

StackOverflowで同様の質問と回答をたくさん読みましたが、私の目的に完全に一致するものは見つかりませんでした。

少し明確にするために、私はルビーを使用しており、繰り返し文字を許可したくありません。

4

5 に答える 5

5

これがあなたの解決策です

^(?:([act])(?!.*\1)){3}$

ここRegexrでそれを参照してください

^                  # matches the start of the string
    (?:            # open a non capturing group 
        ([act])    # The characters that are allowed and a capturing group
        (?!.*\1)   # That character is matched only if it does not occur once more, Lookahead assertion
    ){3}           # Defines the amount of characters
$

唯一の特別な考えは、文字が繰り返されないようにするための先読みアサーションです。

^$は、文字列の開始と終了に一致するアンカーです。

于 2013-01-25T06:53:03.607 に答える
3

[act]{3}または^[act]{3}$、ほとんどの正規表現方言でそれを行います。使用しているシステムを絞り込むことができれば、より具体的な答えを得るのに役立ちます。

編集:以下のコメントで@georgydyerが述べているように、繰り返し文字が許可されているかどうかはあなたの質問からは不明です。そうでない場合は、この質問からの答えを適応させて、次のようにすることができます。

^(?=[act]{3}$)(?!.*(.).*\1).*$

つまり、一致をチェックするための正の先読みと、繰り返される文字を除外するための後方参照を伴う負の先読みです。

于 2013-01-25T00:53:52.830 に答える
2

これが私がそれについて行く方法です:

regex = /\b(?:#{ Regexp.union(str.split('').permutation.map{ |a| a.join }).source })\b/
# => /(?:act|atc|cat|cta|tac|tca)/

%w[
  cat act tca atc tac cta
  ca ac cata
].each do |w|
  puts '"%s" %s' % [w, w[regex] ? 'matches' : "doesn't match"]
end

その出力:

"cat" matches
"act" matches
"tca" matches
"atc" matches
"tac" matches
"cta" matches
"ca" doesn't match
"ac" doesn't match
"cata" doesn't match

Regexp.union私は多くのことに配列を渡す手法を使用しています。gsub私は特にハッシュのキーをうまく処理し、テキストテンプレートをすばやく検索/置換するためにハッシュを渡します。これは、gsubドキュメントの例です。

'hello'.gsub(/[eo]/, 'e' => 3, 'o' => '*') #=> "h3ll*"

Regexp.unionは正規表現を作成します。生成される実際のパターンを抽出するときは、source代わりに使用することが重要です。to_s

puts regex.to_s
=> (?-mix:\b(?:act|atc|cat|cta|tac|tca)\b)

puts regex.source
=> \b(?:act|atc|cat|cta|tac|tca)\b

to_s文字列内にパターンのフラグがどのように埋め込まれているかに注目してください。それらを予期しない場合は、誤ってそのパターンを別のパターンに埋め込んでしまう可能性があります。これは、期待どおりに動作しません。そこに行って、それをして、証拠としてへこんだヘルメットを持ってください。

本当に楽しみたい場合は、CPANで利用可能なPerl Regexp::Assembleモジュールを調べてください。これに加えて、List :: Permutorを使用すると、より複雑なパターンを生成できます。このような単純な文字列では、スペースをあまり節約できませんが、長い文字列や目的のヒットの大きな配列では、大きな違いが生じる可能性があります。残念ながら、Rubyにはこのようなものはありませんが、単語または単語の配列を使用して単純なPerlスクリプトを記述し、正規表現を生成して返すことができます。

use List::Permutor;
use Regexp::Assemble;

my $regex_assembler = Regexp::Assemble->new;
my $perm = new List::Permutor split('', 'act');
while (my @set = $perm->next) {
    $regex_assembler->add(join('', @set));
}
print $regex_assembler->re, "\n";
(?-xism:(?:a(?:ct|tc)|c(?:at|ta)|t(?:ac|ca)))

RubyでRegexp::Assembleを使用する方法の詳細については、「Rubyで何百ものテキスト置換を実行する効率的な方法はありますか? 」を参照してください。

于 2013-01-25T05:20:37.240 に答える
1

間違いありません-ポジティブ/ネガティブな先読みと後方参照を使用する正規表現は洗練されていますが、3文字しか扱っていない場合は、@ sconesが提案するような文字の順列を明示的に列挙することで、冗長性の側で誤りを犯します。

"act".split('').permutation.map(&:join)
=> ["act", "atc", "cat", "cta", "tac", "tca"]

また、より大きな文字列をスキャンするために正規表現が本当に必要な場合は、いつでも次のことができます。

Regexp.union "act".split('').permutation.map(&:join)
=> /\b(act|atc|cat|cta|tac|tca)\b/

明らかに、この戦略は検索文字列が大きくなっても拡張できませんが、私の意見では、このようなコードの意図を観察する方がはるかに簡単です。

編集cata: @theTinManのフィードバックに基づいて、誤検知の単語境界を追加しました。

于 2013-01-25T05:18:34.053 に答える
1

ここではいくつかのことを想定します。-指定された文字の順列を探しています-rubyを使用しています

str = "act"
permutations = str.split(//).permutation.map{|p| p.join("")}

# and for the actual test
permutations.include?("cat")

ただし、正規表現ではありません。

于 2013-01-25T01:07:47.653 に答える