我在RosettaCode上找到了以下Java代码示例:
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
- 我不熟悉Java,但是理解这段代码片段除了正则表达式之外的所有方面
- 我有基本到基本高级的正则表达式知识,如内置的PHP函数中所使用的
.?|(..+?)\\1+
如何匹配素数?
我在RosettaCode上找到了以下Java代码示例:
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
.?|(..+?)\\1+
如何匹配素数?
您说您理解这部分内容,但是为了强调一下,生成的字符串长度等于提供的数字。因此,当且仅当n == 3
时,该字符串具有三个字符。
.?
正则表达式的第一部分表示“任何字符,出现零或一次”。因此,基本上是有零个或一个字符-- 或者按照我上面提到的,n == 0 || n == 1
。如果我们有匹配,则返回其否定。这与零和一不是质数的事实相对应。(..+?)\\1+
正则表达式的第二部分有点棘手,它依赖于分组和反向引用。分组是指括号中的任何内容,它会被正则表达式引擎捕获并存储以备后用。反向引用是指在同一正则表达式中稍后使用的匹配分组。我将在素性测试之外解释正则表达式部分:给定由重复的String t
组成的String s
,下面的正则表达式可以找到t
。
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
(.*)
到\1
中,然后查看是否有\1+
跟在后面。使用^
和$
确保匹配必须是整个字符串。String t
,而正则表达式将找到这样的t
(由于\1
是贪婪的,所以是尽可能长的)。n
的素性,首先生成一个长度为n
的String
(填充相同的char
)。k
的String
捕获到\1
中,并尝试将\1+
与其余的String
匹配。n
是k
的适当倍数,因此n
不是素数。n
外的这样的k
,因此n
是素数。
如何使用.?|(..+?)\1+
匹配质数?
实际上,它不能!它匹配非质数长度的String
!
.?
:备选项的第一部分匹配长度为0
或1
的String
(根据定义不是质数)(..+?)\1+
:备选项的第二部分是正则表达式上面解释过的一个变体,它匹配长度为n
的String
,该String
是长度为k>=2
的String
的“倍数”(即,n
是合成数,不是质数)。
?
实际上不是必要的,但通过首先尝试较小的k
可能有助于加速过程请注意return
语句中的!
布尔补码运算符:它否定了matches
。当正则表达式不匹配时,n
是质数!这是双重否定逻辑,所以这有点令人困惑!!
这是代码的一个简单重写,使其更易读:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
如果给出一个长度为n
的字符串,其中填充了相同的字符,
.{0,1}
检查n=0,1
,不是质数(.{2,})\1+
检查n
是否为k>=2
的proper multiple,不是质数除了对\1
使用勉强的修改符号?
(为了清晰起见而省略),以上正则表达式与原始表达式完全相同。
下面的正则表达式使用类似的技巧;它应该是教育性的:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
很不错的正则表达式技巧(尽管非常低效)... :)
该正则表达式将非质数定义为:
N 不是质数当且仅当 N<=1 或 N 可以被某个大于 1 的数 K 整除。
与其将 N 的简单数字表示传递给正则表达式引擎,更好的方法是使用一个由重复字符组成的长度为 N 的序列。第一部分检查 N 是否等于 0 或 1,第二部分使用反向引用寻找除数 K>1,强制正则表达式引擎查找某个非空子序列,它可以至少重复两次来形成整个序列。如果这样的子序列存在,则意味着该子序列的长度能够整除 N,因此 N 不是质数。
!new String(new char[n]).matches(".?|(..+?)\\1+")
等价于!((new String(new char[n])).matches(".?|(..+?)\\1+"))
。 - Gumbo