Regex 用正则表达式检查数字整除性
给定一个十进制数Regex 用正则表达式检查数字整除性,regex,math,Regex,Math,给定一个十进制数N作为一个数字字符串,如何仅使用正则表达式检查它是否可被M整除,而不转换为int M=2、4、5、10是显而易见的。对于M=3,这里有一些有趣的见解: 有人能为M=7、9、11、13等提供解决方案吗?普通的 测试代码(使用python,但可以随意使用任何语言): 对于那些好奇的人,这里有一个M=3的例子(假设引擎支持递归): Upd:有关更多讨论和示例,请参见此。在那里张贴的表达结果是错误的(在70*N上失败),但“如何到达那里”部分很有教育意义。尽管这个问题很有趣,但我认为除了
N
作为一个数字字符串,如何仅使用正则表达式检查它是否可被M
整除,而不转换为int
M=2、4、5、10是显而易见的。对于M=3,这里有一些有趣的见解:
有人能为M=7、9、11、13等提供解决方案吗?普通的
测试代码(使用python,但可以随意使用任何语言):
对于那些好奇的人,这里有一个M=3
的例子(假设引擎支持递归):
Upd:有关更多讨论和示例,请参见此。在那里张贴的表达结果是错误的(在70*N上失败),但“如何到达那里”部分很有教育意义。尽管这个问题很有趣,但我认为除了你列出的“明显的”问题之外,其他任何问题都不可能 大多数问题都需要数学处理
您可以使用a,这样您就可以将成对的“明显的”组合在一起(2x3、3x5等): 使用
\b\w{6}\b
很容易匹配一个6个字母的单词。匹配一个单词
包含“cat”同样容易:\b\w*cat\w*\b
将这两者结合起来,我们得到:(?=\b\w{6}\b)\b\w*cat\w*\b
分析这一点
带有RegexBuddy的正则表达式。容易的!这就是它的工作原理。在
字符串中尝试正则表达式的每个字符位置,
引擎将首先在正向前瞻中尝试正则表达式。
只有当
字符串中的当前字符位置位于6个字母的开头
字符串中的单词。否则,前瞻将失败,引擎将停止运行
将从下一个字符开始继续尝试正则表达式
在字符串中的位置
如果您的数字是基于一元数的,则可以使用以下正则表达式:
s/1{divisior}//g
,然后测试数字是否为空
下面是一种Perl方法
my @divs = (2,3,5,7,11,13);
for my $num(2..26) {
my $unary = '1'x$num; # convert num to unary
print "\n$num can be divided by : ";
for(@divs) {
my $test = $unary;
$test =~ s/1{$_}//g;
print "$_, " unless $test;
}
}
输出:
2 can be divided by : 2,
3 can be divided by : 3,
4 can be divided by : 2,
5 can be divided by : 5,
6 can be divided by : 2, 3,
7 can be divided by : 7,
8 can be divided by : 2,
9 can be divided by : 3,
10 can be divided by : 2, 5,
11 can be divided by : 11,
12 can be divided by : 2, 3,
13 can be divided by : 13,
14 can be divided by : 2, 7,
15 can be divided by : 3, 5,
16 can be divided by : 2,
17 can be divided by :
18 can be divided by : 2, 3,
19 can be divided by :
20 can be divided by : 2, 5,
21 can be divided by : 3, 7,
22 can be divided by : 2, 11,
23 can be divided by :
24 can be divided by : 2, 3,
25 can be divided by : 5,
26 can be divided by : 2, 13,
如果允许修改字符串并重复,则可以一次执行一步长除法。sed语法为7:重新应用,直到获得剩余部分。当您有单个0、1、2、3、4、5或6时停止
s/^0//
s/^7/0/
s/^8/1/
s/^9/2/
s/^([18]4|[29][18]|35|4[29]|56|63)/0/
s/^([18]5|[29][29]|36|43|5[07]|64)/1/
s/^([18]6|[29]3|3[07]|44|5[18]|65)/2/
s/^([18][07]|[29]4|3[18]|45|5[29]|66)/3/
s/^([18][18]|[29]5|3[29]|46|53|6[07])/4/
s/^([18][29]|[29]6|33|4[07]|54|6[18])/5/
s/^([18]3|[29][07]|34|4[18]|55|6[29])/6/
但这是很淡的酱汁。完全取消“regex”更容易,只需一次读入一个字符并切换到适当的状态。如果这不是一个选项,那么我怀疑你在7和13中运气不佳,尽管11可能仍然是可能的。也许令人惊讶的结果是这样一个正则表达式总是存在的。更不令人惊讶的是,它通常没有用处 存在的结果来自于(DFA)和正则表达式之间的对应关系。让我们做一个DFA。用N表示模数(它不需要是素数),用B表示数字基数,对于普通的十进制数是10。具有N个标记为0到N-1的状态的DFA。初始状态为0。DFA的符号为数字0至B-1。状态表示输入字符串左前缀的剩余部分,当除以N时解释为整数。边表示在右侧添加数字时状态的变化。在算术上,这是状态映射S(状态,数字)=B*状态+数字(模N)。接受状态为0,因为零余数表示可整除性。所以我们有一个DFA。DFA识别的语言与正则表达式识别的语言相同,因此存在一种。因此,虽然这很有趣,但它没有帮助,因为它没有告诉您如何确定表达式 如果您想要一个通用算法,那么很容易在运行时构建这样的DFA,并通过直接计算填充其状态表。初始化只是一对运行时为O(M*N)的嵌套循环。机器识别每个输入字符的时间是恒定的。这是非常快的,但不使用regexp库,如果这是您真正需要的 在获得实际的正则表达式时,我们需要考虑。根据这个定理,我们知道B^(N-1)==1(模N)。例如,当N=7和B=10时,这意味着每一个6位数的块都相当于0范围内的某个单位数。。6为了可分割性的目的。指数可以小于N-1;一般来说,它是N的一个因子。调用块D的大小。有N个正则表达式用于D个数字的块,每个正则表达式表示模N的余数的一个特定等价类。这些表达式最多有长度O(B^D),这是大的。对于N=7,这是一组一百万个字符长的正则表达式;我想这会破坏大多数regexp库 这与示例代码中的表达式如何工作有关;表达式
(?1)
匹配的字符串等于0(mod 3)。这适用于N=3,因为10^1==1(mod 3),这意味着A0B==AB(mod 3)。当指数大于1时,情况更为复杂,但原理相同。(请注意,示例代码使用的识别器严格来说不仅仅是正则表达式。)表达式[0369]
、[147]
和[258]
是模3表达式中数字0、1和2的正则表达式。一般来说,您将以类似的方式使用上面的regexp数字
我不提供代码是因为(1)编写代码的时间比这个答案要长,(2)我真的怀疑它在任何已知的实现中都不会执行。这里是一个通用的直接递归蛮力长除法。它并没有经过优化,也绝对不是优雅的lol。它是用JavaScript编写的(下面是一个带有代码的测试html页面):
这是一个古老的问题,但现有的答案中没有一个包含代码。早在2010年,我就编写了计算这些正则表达式的代码,并且有一个到的链接,所以我认为在这里添加一个链接可能会很有用 该技术基本上与exc中所述的技术相同
2 can be divided by : 2,
3 can be divided by : 3,
4 can be divided by : 2,
5 can be divided by : 5,
6 can be divided by : 2, 3,
7 can be divided by : 7,
8 can be divided by : 2,
9 can be divided by : 3,
10 can be divided by : 2, 5,
11 can be divided by : 11,
12 can be divided by : 2, 3,
13 can be divided by : 13,
14 can be divided by : 2, 7,
15 can be divided by : 3, 5,
16 can be divided by : 2,
17 can be divided by :
18 can be divided by : 2, 3,
19 can be divided by :
20 can be divided by : 2, 5,
21 can be divided by : 3, 7,
22 can be divided by : 2, 11,
23 can be divided by :
24 can be divided by : 2, 3,
25 can be divided by : 5,
26 can be divided by : 2, 13,
s/^0//
s/^7/0/
s/^8/1/
s/^9/2/
s/^([18]4|[29][18]|35|4[29]|56|63)/0/
s/^([18]5|[29][29]|36|43|5[07]|64)/1/
s/^([18]6|[29]3|3[07]|44|5[18]|65)/2/
s/^([18][07]|[29]4|3[18]|45|5[29]|66)/3/
s/^([18][18]|[29]5|3[29]|46|53|6[07])/4/
s/^([18][29]|[29]6|33|4[07]|54|6[18])/5/
s/^([18]3|[29][07]|34|4[18]|55|6[29])/6/
<!doctype html>
<html>
<head>
<script type="text/javascript">
function isNDivisibleByM(N, M) {
var copyN = N;
var MLength = (""+M).length;
var multiples = [];
for(var x = 0; x < M; x++)
multiples[x] = [];
for(var i = M, x=0; i < M*10; x=0) {
for(var j = i; j < i+M; j++, x++)
multiples[x].push(j);
i+=M;
}
var REs = [];
for(var x = 0; x < M; x++)
REs[x] = new RegExp("^("+multiples[x].join("|")+")");
while(N.length >= MLength) {
var sameLen = (N.length == MLength);
for(var x = 0; x < M; x++)
N = N.replace(REs[x], (x==0)?"":(""+x));
N = N.replace(/^0/g, "");
if(sameLen) break;
}
N = N.replace(/^0/g, "");
var numericN = parseInt(copyN);
if(N.length == 0) {
if(numericN%M!=0) {
console.error("Wrong claim: " + copyN + " NOT divisible by " + M);
}
return true;
}
if(numericN%M==0 && N.length != 0) {
console.error("Missed claim: " + copyN + " IS divisible by " + M + " - " + N + " is: " + copyN);
}
return false;
}
function run() {
alert(isNDivisibleByM((""+document.getElementById("N").value), parseInt(document.getElementById("M").value)));
}
</script>
</head>
<body>
<label>N:</label><input type="text" id="N" />
<label>M:</label><input type="text" id="M" />
<button onclick="run()">Is N divisible by M?</button>
</body>
</html>
while(numStr.length > 1) {
numStr = numStr.replace(/^(14|21|35|42|56|63)/, "");
numStr = numStr.replace(/^(15|22|36|43|50|64)/, "1");
numStr = numStr.replace(/^(16|23|30|44|51|65)/, "2");
numStr = numStr.replace(/^(10|24|31|45|52|66)/, "3");
numStr = numStr.replace(/^(11|25|32|46|53|60)/, "4");
numStr = numStr.replace(/^(12|26|33|40|54|61)/, "5");
numStr = numStr.replace(/^(13|20|34|41|55|62)/, "6");
}