実際に何が起こるか
+
範囲数量詞が続くと、範囲数量詞に所有格が提供されないようです。むしろ、前に1回以上繰り返されたものとして扱われます。.{1,3}+b
例として使用すると、と同等になります(?:.{1,3})+b
。
回避策
これは、より一般的なコンストラクトの非バックトラッキンググループ(またはアトミックグループ化)で回避でき(?>pattern)
ます。pattern{n,m}+
一般的なケースを例として使用して、非バックトラッキンググループを使用して同等の正規表現を作成しましょう(と一致する場合のJavaの動作に相当しますpattern{n,m}+
)。
(?>(?>pattern){n,m})
なぜ2レベルの非バックトラッキンググループなのですか?2が必要な理由:
- (繰り返しの1つのインスタンス)に一致するものが見つかった場合、
pattern
内部でのバックトラックpattern
は許可されません。(インスタンスが見つからない限り、内部でのバックトラックpattern
が許可されることに注意してください)。これは、内部の非バックトレースグループでエミュレートされます。
- のインスタンスがこれ以上
pattern
見つからない場合、インスタンスを削除するためのバックトラックは許可されません。これは、外側の非バックトラッキンググループでエミュレートされます。
ここに注意点があるかどうかはわかりません。この方法でエミュレートされていないケースを見つけた場合は、コメントで私にpingしてください。
テスト
テスト1
最初に、私はこの正規表現をテストしました:
(.{1,3}+)b
最初はキャプチャグループなしでテストしましたが、結果が非常に驚くべきものだったため、キャプチャグループで何が起こっているのかを確認する必要がありました。
この入力について:
2343333ab
その結果、文字列全体がに一致し、キャプチャグループがキャプチャされます2343333a
(b
末尾にがありません)。これは、上限がなんらかの形で破られていることを示しています。
rubularでのデモ
テスト2
この2番目のテストは、範囲数量詞の動作を所有格{n}
に変更できないことを明らかにします。これは、他の範囲数量詞とにも当てはまる可能性があります。代わりに、以下は1回以上の時間動作の繰り返しのみを示します。{n,}
{n,m}
+
(私の最初の結論は+
、上限を上書きするということですが、それは間違っていることがわかりました)。
正規表現のテスト:
(.{3}+)b
入力文字列:
23d4344333ab
234344333ab
23434433ab
キャプチャグループ1でキャプチャされた一致は、すべて3の倍数です。上から下に、正規表現は入力文字列に対してそれぞれ2、1、0文字をスキップします。
注釈付きの入力文字列([]
正規表現全体に一致することを()
示し、グループ1をキャプチャすることによってキャプチャされたテキストを示します):
23[(d4344333a)b]
2[(34344333a)b]
[(23434433a)b]
rubularでのデモ
回避策のテストコード
これは、外部と内部の両方の非バックトラッキンググループが必要であることを示すJavaのテストコードです。イデオネ
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<"));
}
}