2013-03-20 8 views
7

所有する量指定子は貪欲で、バックトラックを拒否します。正規表現/.{1,3}+b/は、以下を意味する必要があります。改行を除くすべての文字に1〜3回、可能な限り一致させ、バックトラックしないでください。文字はbと一致します。この例では所有している総称量子{m、n} +はRuby 1.9.3で実装されていませんか?

'ab'.sub /.{1,3}+b/, 'c' #=> "c" 

無置換が事実に反し場所を取る必要があります。この2つの例で

結果が異なります。

'aab'.sub /.{0,1}+b/, 'c' #=> "c" 
'aab'.sub /.?+b/, 'c'  #=> "ac" 

は、彼らが同じ答えを与えるスカラ座、とこれを比較します

scala> ".{0,1}+b".r.replaceAllIn("aab", "c") 
res1: String = ac 
scala> ".?+b".r.replaceAllIn("aab", "c") 
res2: String = ac 

これはRubyのバグで、またはそれがやる気にさせることも可能ですこの行動は?おそらく、何らかの理由でOnigurumaは、総量限定子{m,n}を除いて、すべての量限定子で所有者を実装した?*+?その場合、なぜですか?本当に何が起こる

+0

Onigurumaが範囲限定子の所有権を無効にしている理由はわかりません - おそらくあなたは関係する人々に尋ねるべきです。 – nhahtdh

答えて

2

これは、Onigurumaのようです。 Documentation{n,m}+, {n,}+, {n}+ are possessive op. in ONIG_SYNTAX_JAVA onlyと言います。私はこれが後方互換性の理由のためだと思いますか?

5

レンジ数量詞が続く+が範囲数量詞へ所有プロパティを提供していないようです。むしろ、それは何度も何度も繰り返されたものとして扱われます。例として.{1,3}+bを使用すると、(?:.{1,3})+bに相当します。

回避策

あなたはこのより一般的な構造非バックトラックグループ(またはアトミックグループ)(?>pattern)とアラウンドを動作することができます。私たちは(Javaの動作に相当pattern{n,m}+とのマッチング)非バックトラック群と同等の正規表現を構築するための例として、一般的なケースpattern{n,m}+を使用してみましょう:

(?>(?>pattern){n,m}) 

非バックトラックグループのなぜ2つのレベル?

  • 一致がpattern(繰り返しの1つのインスタンス)のために発見された場合に禁止されているpattern内にバックトラック、次の理由2が必要です。 (インスタンスが見つからない限り、バックトラッキングはpattern以内であることに注意してください)。これは、バックトラッキングのない内部のグループでエミュレートされます。
  • patternのインスタンスがそれ以上見つからない場合、インスタンスを削除するためのバックトラッキングは許可されません。これはバックトラッキング外のグループでエミュレートされます。

ここに警告があるかどうかわかりません。この方法でエミュレートされていないケースが見つかった場合は、私にpingしてください。

テスト

最初は、私はこの正規表現テスト1

テスト:最初

(.{1,3}+)b 

が、私はキャプチャグループなしでテストしたが、結果は私が必要とするので、驚くべきことでしたキャプチャグループは何が起こっているかを確認します。この入力に

2343333ab 

結果は、文字列全体がと一致し、そして捕捉基(末端にbなし)2343333aを捕獲ことです。これは、上限が何らかの形で壊れていることを示しています。範囲は{n}の挙動が所有なるように変更することができない数量方法

DEMO at rubular

テスト2

この第二の試験は明らかにし、他の範囲に適用{n,}{n,m}を数量と思われます。代わりに、次の+は1回以上の繰り返しの動作しか示さない。

(私の最初の結論は、+は上限を上書きしますが、間違っていることが判明しています)。

試験正規表現:

(.{3}+)b 

入力文字列:

23d4344333ab 
234344333ab 
23434433ab 

グループ1を捕捉するに捕捉マッチは、正規表現が2をスキップし、上から下へ3.すべての倍数である1入力文字列にはそれぞれ0文字を使用します。

回避するため

23[(d4344333a)b] 
2[(34344333a)b] 
[(23434433a)b] 

DEMO at rubular

テストコード:注釈付き

入力文字列([]全体正規表現の一致を示し、()グループ1をキャプチャによってキャプチャテキストを表します)これは、Javaのテストコードで、バックトラッキングのない外部グループと内部の両方が必要であることを示しています。 ideone

class TestPossessive { 
    public static void main(String args[]) { 
    String inputText = "123456789012"; 
    System.out.println("Input string: " + inputText); 
    System.out.println("Expected: " + inputText.replaceFirst("(?:\\d{3,4}(?![89])){2,}+", ">$0<")); 
    System.out.println("Outer possessive group: " + inputText.replaceFirst("(?>(?:\\d{3,4}(?![89])){2,})", ">$0<")); 
    System.out.println("Inner possessive group: " + inputText.replaceFirst("(?>\\d{3,4}(?![89])){2,}", ">$0<")); 
    System.out.println("Both: " + inputText.replaceFirst("(?>(?>\\d{3,4}(?![89])){2,})", ">$0<")); 

    System.out.println(); 

    inputText = "aab"; 
    System.out.println("Input string: " + inputText); 
    System.out.println("Expected: " + inputText.replaceFirst(".{1,3}+b", ">$0<")); 
    System.out.println("Outer possessive group: " + inputText.replaceFirst("(?>.{1,3})b", ">$0<")); 
    System.out.println("Inner possessive group: " + inputText.replaceFirst("(?>.){1,3}b", ">$0<")); 
    System.out.println("Both: " + inputText.replaceFirst("(?>(?>.){1,3})b", ">$0<")); 
    } 
} 

+0

ありがとうございます。私は '{m、n} +'が2つの連続する量子になるという結論に達しました。 @rubular.com/r/sMG8aWrnYDとhttp://rubular.com/r/e9O10dNQxAの違いを参照してください。 –

+0

@StaffanNöteberg:はい、私はまたその半分の方法を認識し、私の答えを変えました。 (あなたが最初の2〜3分で私の答えを読んでいれば)。 – nhahtdh

+0

偉大な心は似ていると思います;-) –

関連する問題