素数性テスト以外の正規表現部分について説明します。次の正規表現String s
は、 の繰り返しで構成されるa を指定するとString t
、 が見つかりt
ます。
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
それが機能する方法は、正規表現が にキャプチャ(.*)
し\1
、それを\1+
フォローしているかどうかを確認することです。and を使用する^
と$
、文字列全体が一致する必要があります。
したがって、ある意味で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
orの交互一致の最初の部分1
(定義により素数ではない)
(..+?)\1+
: 代替の 2 番目の部分は、上記で説明した正規表現のバリエーションであり、長さの「倍数」である長さの一致(つまりString
、合成であり、素数ではありません)。
n
String
k >= 2
n
- reluctant 修飾子は正確さのために実際には必要ないことに注意してください
?
。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
?
reluctant 修飾子on (わかりやすくするために省略) を除いて\1
、上記の正規表現は元の正規表現と同じです。
もっと楽しい正規表現
次の正規表現は、同様の手法を使用しています。それは教育的であるべきです:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
こちらもご覧ください