当使用line-begin& amp;时,我在C#的正则表达式匹配中遇到后瞻断言的问题。线端锚。 在下面的示例中,正则表达式B的行为完全符合我的预期(并在此处记录:https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference
我最初对RegEx A与第1行不匹配感到惊讶。现在我想我理解为什么RegEx A与第1行不匹配。[因为断言是零宽度 - 表达式基本上是^ \ d {2} $,这显然与4位数年份不匹配 - 这就是为什么它与第6和第6行相匹配的原因。 7]。
我知道我可以像这样重写正面断言(RegEx A):^ 19 \ d {2} $。
但我的最终目标是像RegEx C这样的正则表达式 - 使用否定断言来查找不以给定前缀开头的所有字符串。也就是说,我正在尝试使用负断言创建一个表达式,该表达式对第3行和第4行返回true而不是5-7。
RegEx D是来自C#文档的类似负面断言样本,但不使用开始/结束锚点,对于第3行和第4行也是如此,但也是5-7。
考虑到这一点,我怎样才能使负判断(如RegEx C)与line-begin / -end锚点一起使用,以便它在验证输入是单行的情况下像RegEx D中的示例那样起作用?
我想知道使用断言是否根本不可能。这意味着另一种选择是表达评估异常否定的所有正面案例(类似于在正则表达式E中使用19),但当目标是排除一个时,表达一大堆积极因素是不可能或不切实际的。特别单一(也许是复杂的)案例。
谢谢!
示例程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace RegExTest
{
class Program
{
static void Main(string[] args)
{
string[] reList = new string[]
{
@"^(?<=19)\d{2}$", // RegEx A
@"(?<=19)\d{2}", // RegEx B
@"^(?<!19)\d{2}$", // RegEx C
@"(?<!19)\d{2}\b", // RegEx D
@"^19\d{2}$", // RegEx E
};
string[] tests = new string[]
{
"1999", // Line 1
"1851 1999 1950 1905 2003", // Line 2
"1895", // Line 3
"2095", // Line 4
"195", // Line 5
"18", // Line 6
"19", // Line 7
};
foreach (var r in reList)
{
var re = new Regex(r);
Console.WriteLine("");
Console.WriteLine($"{r}");
Console.WriteLine("==========================");
foreach (var s in tests)
{
Console.WriteLine($"{s}={re.IsMatch(s)}");
if (re.IsMatch(s))
{
foreach (Match m in re.Matches(s))
{
Console.WriteLine($"Match @ ({m.Index}, {m.Length})");
}
}
}
}
}
}
}
输出:
^(?<=19)\d{2}$
==========================
1999=False
1851 1999 1950 1905 2003=False
1895=False
2095=False
195=False
18=False
19=False
(?<=19)\d{2}
==========================
1999=True
Match @ (2, 2)
1851 1999 1950 1905 2003=True
Match @ (7, 2)
Match @ (12, 2)
Match @ (17, 2)
1895=False
2095=False
195=False
18=False
19=False
^(?<!19)\d{2}$
==========================
1999=False
1851 1999 1950 1905 2003=False
1895=False
2095=False
195=False
18=True
Match @ (0, 2)
19=True
Match @ (0, 2)
(?<!19)\d{2}\b
==========================
1999=False
1851 1999 1950 1905 2003=True
Match @ (2, 2)
Match @ (22, 2)
1895=True
Match @ (2, 2)
2095=True
Match @ (2, 2)
195=True
Match @ (1, 2)
18=True
Match @ (0, 2)
19=True
Match @ (0, 2)
^19\d{2}$
==========================
1999=True
Match @ (0, 4)
1851 1999 1950 1905 2003=False
1895=False
2095=False
195=False
18=False
19=False
答案 0 :(得分:3)
您将使用普通模式的默认行为混淆外观断言。外观断言这意味着它不消耗字符。
它查找一个条件,如果它满足则将光标带回到它开始的位置,否则它会使引擎回溯或立即失败。
正则表达式A ^(?<!19)\d{2}$
不应与字符串1 1999
匹配,因为引擎的工作方式如下:
^
断言字符串的开头(我们在位置0)(?<!19)
检查前面的字符是否不是19
(肯定是在
位置0我们没有前面的字符所以这满足)\d{2}
消耗两位数字(我们位于第2位)$
断言字符串的结尾(实际上我们还有2个字符可以到达
字符串结束,因此引擎立即失败)所以你必须这样做^\d{2}(?<!19)\d{2}$
或^(?!19)\d{4}$
第二个更合适。