C# 这个正则表达式如何找到三角数?
作为教育性regex系列文章的一部分,这是对嵌套引用概念的温和介绍 前几项是: 有很多方法可以检查一个数字是否是三角形的。有一种有趣的技术使用正则表达式,如下所示:C# 这个正则表达式如何找到三角数?,c#,java,regex,capturing-group,nested-reference,C#,Java,Regex,Capturing Group,Nested Reference,作为教育性regex系列文章的一部分,这是对嵌套引用概念的温和介绍 前几项是: 有很多方法可以检查一个数字是否是三角形的。有一种有趣的技术使用正则表达式,如下所示: 给定n,我们首先创建一个长度为n的字符串,用相同的字符填充 然后,我们将该字符串与模式^(\1.|^.)+$匹配 n是三角形的当且仅当此图案与字符串匹配 以下是一些代码片段,说明这在几种语言中都可以使用: for(int n=0;n解释 下面是该模式的示意图分解: from beginning… | …to
- 给定n,我们首先创建一个长度为n的字符串,用相同的字符填充
- 然后,我们将该字符串与模式
匹配^(\1.|^.)+$
- n是三角形的当且仅当此图案与字符串匹配
for(int n=0;n解释
下面是该模式的示意图分解:
from beginning…
| …to end
| |
^(\1.|^.)+$
\______/|___match
group 1 one-or-more times
(…)
定义捕获组1,此组为+
。此子模式为^
和$
,以查看它是否可以匹配整个字符串
第1组尝试匹配此|那个
:
,即第1组匹配的(自我参考!),加上\1.
- 或
,即,仅在开头的一个字符中“任意”一个^.
+
的第一次迭代中,组1还没有捕获任何内容(这与说它以空字符串开始不同)。因此引入了第二种替代方法,作为“初始化”的一种方式组1,即允许在字符串开头捕获一个字符
因此,当使用+
重复时,组1首先尝试匹配1个字符,然后是2个,然后是3个,然后是4个,以此类推。这些数字的总和是一个三角形数字
进一步探索 请注意,为了简化,我们使用了与输入相同的重复字符组成的字符串。现在我们知道了此模式的工作原理,我们可以看到此模式还可以匹配字符串,如
“1121231234”
,“aababc”
,等等
还请注意,如果我们发现n是一个三角形数字,即n=1+2+…+k,则组1在末尾捕获的字符串长度将为k
以下C#代码段()中显示了这两点:
Regex r=newregex(@“^(\1.|^.)+$”;
Console.WriteLine(r.IsMatch(“aababc”);//True
Console.WriteLine(r.IsMatch(“1121231234”);//True
Console.WriteLine(r.IsMatch(“iLoveRegEx”);//False
对于(int n=0;n此系列是通过社区()中某些人的权限启动的。如果接待情况良好,我计划继续介绍regex的其他更高级和更基本的功能。如果这是为了教育和社区,为什么不是社区wiki?我认为这项努力值得一些声誉。请不要强迫他们进入社区wiki。谁在乎poly从44k变为50k,d是什么区别?我期待着这个系列。请注意,如果你对正则表达式的起源感兴趣,我开始写一个关于它的博客系列。不幸的是,我从来没有完成过它。如果这是一个系列-发明一个标签如何,这将简化查找这个系列的所有“文章”?请注意具有讽刺意味的是,有一些正则表达式库可以匹配这种模式,这就是所谓的“正则”表达式不是正则表达式的证据。“正则语言”的形式定义大致上是“一组字符串,这些字符串正是由具有有限数目的内部状态的匹配机器匹配的字符串”,但知道“我以前匹配的东西”理论上需要无限数量的状态。@Eric-那么我猜你会称它们为不规则表达式吗?@Eric,@Chaos我在理论计算机科学StackExchange beta上问了一个问题。形式正则表达式只有
$r = '/^(\1.|^.)+$/';
foreach (range(0,50) as $n) {
if (preg_match($r, str_repeat('o', $n))) {
print("$n ");
}
}
for (int n = 0; n <= 50; n++) {
String s = new String(new char[n]);
if (s.matches("(\\1.|^.)+")) {
System.out.print(n + " ");
}
}
Regex r = new Regex(@"^(\1.|^.)+$");
for (int n = 0; n <= 50; n++) {
if (r.IsMatch("".PadLeft(n))) {
Console.Write("{0} ", n);
}
}
from beginning…
| …to end
| |
^(\1.|^.)+$
\______/|___match
group 1 one-or-more times
Regex r = new Regex(@"^(\1.|^.)+$");
Console.WriteLine(r.IsMatch("aababc")); // True
Console.WriteLine(r.IsMatch("1121231234")); // True
Console.WriteLine(r.IsMatch("iLoveRegEx")); // False
for (int n = 0; n <= 50; n++) {
Match m = r.Match("".PadLeft(n));
if (m.Success) {
Console.WriteLine("{0} = sum(1..{1})", n, m.Groups[1].Length);
}
}
// 1 = sum(1..1)
// 3 = sum(1..2)
// 6 = sum(1..3)
// 10 = sum(1..4)
// 15 = sum(1..5)
// 21 = sum(1..6)
// 28 = sum(1..7)
// 36 = sum(1..8)
// 45 = sum(1..9)