我将解释正则表达式部分之外的素数测试:以下正则表达式,给定一个由重复组成的正则表达式,发现 。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
)
- 正则表达式将一定长度(比如)的 a 捕获到 中,并尝试与其余部分匹配
String
k
\1
\1+
String
- 如果存在匹配项,则 是 的真倍数,因此不是素数。
n
k
n
- 如果没有匹配,则不存在除以 的匹配,因此是素数
k
n
n
如何匹配素数?.?|(..+?)\1+
实际上,事实并非如此!它匹配谁的长度不是素数!String
-
.?
:交替的第一部分与长度匹配或(根据定义不是素数)String
0
1
-
(..+?)\1+
:交替的第二部分,上面解释的正则表达式的变体,匹配的长度是长度的“倍数”(即 是一个复合体,而不是素数)。String
n
String
k >= 2
n
- 请注意,不情愿的修饰符实际上不是正确性所必需的,但它可以通过首先尝试较小的修饰符来帮助加快该过程
?
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 (为清楚起见省略),上述正则表达式与原始正则表达式相同。?
\1
更多有趣的正则表达式
以下正则表达式使用类似的技术;它应该是教育性的:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
另请参见