素数性テスト以外の正規表現の部分について説明します。次の正規表現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
長さのを生成しますn
char
- 正規表現は
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+"))
です。