素数性テスト以外の正規表現の部分について説明します。次の正規表現String sは、繰り返しで構成されるを指定するとString t、を見つけtます。
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
それが機能する方法は、正規表現がにキャプチャ(.*)し\1、その後に\1+続くかどうかを確認することです。^および$を使用すると、文字列全体と一致する必要があります。
つまり、ある意味でString s、の「倍数」であるが与えられ、String t正規表現はそのようなものを見つけますt(\1貪欲なので、可能な限り長くなります)。
この正規表現が機能する理由を理解したら、(今のところOPの正規表現の最初の代替を無視して)素数性テストにどのように使用されるかを説明するのは簡単です。
- の素数性をテストするには
n、最初に(同じで満たされた)String長さのを生成しますnchar
- 正規表現は
String、ある長さ(たとえばk)をに取り込み\1、\1+残りの部分と一致させようとしますString
- 一致する場合、
nはの適切な倍数であるkため、n素数ではありません。
- 一致するものがない場合には、そのようなは、
kその分裂を存在しないn、とnので素数であります
.?|(..+?)\1+素数をどのように照合しますか?
実際にはそうではありません!長さが素数ではない人と一致し Stringます!
.?:String長さの代替一致の最初の部分0または1(定義により素数ではない)
(..+?)\1+:交互の第2の部分は、正規表現のバリエーションは、上記説明し、一致String長nの「複数」であるString長さのk >= 2(すなわちn、複合、NOT素数です)。
- 消極的修飾子がいることを注意
?実際正しさは必要ありませんが、それは小さな試みることによってプロセスのスピードアップを助けるかもしれないk最初の
ステートメントの! boolean補数演算子に注意してreturnください。これはを否定しmatchesます。それは正規表現が一致しないときです、n素数です!これはダブルネガティブロジックなので、混乱するのも不思議ではありません。
単純化
次に、コードを読みやすくするための簡単なコードの書き換えを示します。
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
上記は基本的に元のJavaコードと同じですが、ロジックを理解しやすくするためにローカル変数に割り当てられた複数のステートメントに分割されています。
次のように、有限反復を使用して正規表現を簡略化することもできます。
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
再び、同じString長さのが与えられたn場合char、
.{0,1}n = 0,1プライムではないかどうかをチェックします
(.{2,})\1+が素数nではなくの適切な倍数であるかどうかをチェックしますk >= 2
?on reluctant modifier on \1(明確化のため省略)を除いて、上記の正規表現は元の正規表現と同じです。
より楽しい正規表現
次の正規表現は同様の手法を使用しています。それは教育的であるべきです:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
こちらもご覧ください
!new String(new char[n]).matches(".?|(..+?)\\1+")と同等!((new String(new char[n])).matches(".?|(..+?)\\1+"))です。