説明
パターンの概略図は次のとおりです。
from beginning…
| …to end
| |
^(\1.|^.)+$
\______/|___match
group 1 one-or-more times
(…)
角かっこはキャプチャグループ1を定義し、このグループは。と繰り返し一致し+
ます。このサブパターンはとで固定され^
、$
文字列全体と一致するかどうかを確認します。
グループ1はthis|that
代替案を照合しようとします:
\1.
、つまり、グループ1が一致したもの(自己参照!)に加えて、「任意の」文字の1つ、
- または
^.
、つまり、最初の「任意の」1文字
グループ1には、グループ1が一致したものへの参照があることに注意してください。これはネストされた/自己参照であり、この例で紹介されている主なアイデアです。キャプチャグループが繰り返される場合、通常は最後のキャプチャのみが保持されるため、この場合の自己参照は基本的に次のようになります。
「前回一致したものに加えて、もう1つ一致させてみてください。今回はそれを一致させます。」
再帰と同様に、自己参照を伴う「基本ケース」が必要です。の最初の反復では+
、グループ1はまだ何もキャプチャしていませんでした(これは、空の文字列で始まると言っているのと同じではありません)。したがって、グループ1を「初期化」する方法として、2番目の代替が導入されます。これは、文字列の先頭にあるときに1つの文字をキャプチャできるようにすることです。
したがって、で繰り返されるように+
、グループ1は最初に1文字、次に2、次に3、次に4などと一致しようとします。これらの数値の合計は三角数です。
さらなる探求
簡略化のために、入力と同じ繰り返し文字で構成される文字列を使用したことに注意してください。このパターンがどのように機能するかがわかったので、このパターンが、など"1121231234"
の文字列にも一致することがわかります。"aababc"
また、nが三角数、つまりn = 1 + 2+…+kであることがわかった場合、最後にグループ1によってキャプチャされた文字列の長さはkになります。
これらのポイントは両方とも、次のC#スニペット(ideone.comにも表示されます)に示されています。
Regex r = new Regex(@"^(\1.|^.)+$");
Console.WriteLine(r.IsMatch("aababc")); // True
Console.WriteLine(r.IsMatch("1121231234")); // True
Console.WriteLine(r.IsMatch("iLoveRegEx")); // False
for (int n = 0; n <= 50; n++) {
Match m = r.Match("".PadLeft(n));
if (m.Success) {
Console.WriteLine("{0} = sum(1..{1})", n, m.Groups[1].Length);
}
}
// 1 = sum(1..1)
// 3 = sum(1..2)
// 6 = sum(1..3)
// 10 = sum(1..4)
// 15 = sum(1..5)
// 21 = sum(1..6)
// 28 = sum(1..7)
// 36 = sum(1..8)
// 45 = sum(1..9)
フレーバーノート
すべてのフレーバーがネストされた参照をサポートしているわけではありません。使用しているフレーバーの癖を常によく理解してください(したがって、正規表現関連の質問をするときは常に、この情報を提供するのに役立ちます)。
ほとんどのフレーバーでは、標準の正規表現マッチングメカニズムは、パターンが入力文字列の任意の部分(おそらく、必ずしもそうとは限りませんが、入力全体)に一致するかどうかを確認しようとします。つまり、必要に応じて^
、$
常にパターンを固定することを忘れないでください。
Javaはその点でわずかに異なり、String.matches
入力文字列全体に対してパターンを一致させようとしPattern.matches
ます。これが、上記のスニペットでアンカーを省略できる理由です。Matcher.matches
\A
他のコンテキストでは、代わりに\Z
アンカーを使用する必要がある場合があることに注意してください。たとえば、複数行モードでは、入力の各行の最初と最後を一致^
させます。$
最後に、.NET正規表現では、繰り返しキャプチャグループによって作成されたすべての中間キャプチャを実際に取得できます。ほとんどのフレーバーでは、できません。すべての中間キャプチャが失われ、最後のキャプチャのみを保持できます。
関連する質問
ボーナス素材:正規表現を使用して2の力を見つけます!!!
わずかな変更を加えるだけで、ここで紹介したのと同じ手法を使用して、2の累乗を見つけることができます。
利用したい基本的な数学的特性は次のとおりです。
- 1 = 1
- 2 =(1)+ 1
- 4 =(1 + 2)+ 1
- 8 =(1 + 2 + 4)+ 1
- 16 =(1 + 2 + 4 + 8)+ 1
- 32 =(1 + 2 + 4 + 8 + 16)+ 1
解決策を以下に示します(ただし、最初に自分で解決してみてください!!!!)
( PHP、Java、およびC#のideone.comを参照してください):
^(\1\1|^.)*.$