如何使用带有线锚的 C# 正则表达式 Lookbehind

布拉德

在 C# 的正则表达式匹配中,我在使用行开始和行结束锚时遇到后视断言的问题。在下面的示例中,Regex 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 行和第 7 行]。

我知道我可以像这样重写肯定断言(RegEx A):^19\d{2}$。

但我的最终目标是像 RegEx C 这样的正则表达式——使用否定断言来查找所有不以给定前缀开头的字符串。也就是说,我试图创建一个带有否定断言的表达式,该表达式对于第 3 行和第 4 行而不是第 5-7 行返回 true。

RegEx D 是来自 C# 文档的类似否定断言示例,但不使用开始/结束锚点,适用于第 3 行和第 4 行,也适用于第 5-7 行。

考虑到这一点,我如何使否定断言(如 RegEx C)与 line-begin/-end 锚一起使用,以便在验证输入是单行时,它的功能类似于 RegEx D 中的示例?

我想知道这是否根本不可能使用断言。这意味着另一种方法是表达所有评估为否定异常的正例(类似于在 Regex 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
雷沃

您将环视断言与正常模式的默认行为混淆了。环视断言这意味着它不消耗字符。

它寻找一个条件,如果它满足然后将光标带回到它开始的地方,否则它会使引擎回溯或立即失败。

正则表达式 A^(?<!19)\d{2}$不应该匹配字符串 1,1999因为引擎是这样工作的:

  1. ^ 断言字符串的开头(我们在位置 0)
  2. (?<!19)检查前面的字符是否不是19(肯定在位置 0 我们没有前面的字符所以这满足)
  3. \d{2} 消耗两位数(我们在位置 2)
  4. $ 断言字符串结尾(实际上我们还有 2 个字符可以到达字符串结尾,因此引擎立即失败)

所以你必须这样做,^\d{2}(?<!19)\d{2}$或者^(?!19)\d{4}$说第二种更合适。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在C#正则表达式中使用lookbehind以删除换行符?

来自分类Dev

php中的正则表达式,带有负数lookbehind

来自分类Dev

如何将此正则表达式转换为不使用Lookbehind?

来自分类Dev

C ++使用正则表达式搜索“正则表达式运算符”

来自分类Dev

具有lookbehind和lookahead的Python正则表达式不起作用

来自分类Dev

具有lookbehind和lookahead的Python正则表达式不起作用

来自分类Dev

如何为包含lookbehind和lookahead的正则表达式拆分字符串

来自分类Dev

如何在javascript正则表达式中不选择lookbehind单词

来自分类Dev

使用Java进行正则表达式Lookahead和Lookbehind

来自分类Dev

LookBehind 正则表达式的语法

来自分类Dev

如何使用正则表达式C ++?

来自分类Dev

如何正则表达式匹配a / b / c ...?

来自分类Dev

如何在C ++中注释正则表达式?

来自分类Dev

使用C#查找日期的正则表达式

来自分类Dev

使用正则表达式C#验证密码

来自分类Dev

使用正则表达式时C ++程序崩溃

来自分类Dev

使用C ++正则表达式,结果太慢

来自分类Dev

在C中使用POSIX正则表达式

来自分类Dev

在C中使用正则表达式

来自分类Dev

正则表达式,使用C#查找日期

来自分类Dev

使用C ++正则表达式和太慢的结果

来自分类Dev

使用变量n正则表达式c#

来自分类Dev

(C#正则表达式)如何使用正则表达式使单词边界适用于括号?

来自分类Dev

如何在C ++中对多个正则表达式使用正则表达式“分组”?

来自分类Dev

无法使用PCRE表达式的C ++正则表达式?

来自分类Dev

在C ++中直接在表达式中使用正则表达式捕获

来自分类Dev

在C ++中直接在表达式中使用正则表达式捕获

来自分类Dev

在C#中使用正则表达式(正则表达式)从字符串获取值

来自分类Dev

Perl正则表达式查找打包结构的名称,而无需使用可变长度的lookbehind?

Related 相关文章

  1. 1

    如何在C#正则表达式中使用lookbehind以删除换行符?

  2. 2

    php中的正则表达式,带有负数lookbehind

  3. 3

    如何将此正则表达式转换为不使用Lookbehind?

  4. 4

    C ++使用正则表达式搜索“正则表达式运算符”

  5. 5

    具有lookbehind和lookahead的Python正则表达式不起作用

  6. 6

    具有lookbehind和lookahead的Python正则表达式不起作用

  7. 7

    如何为包含lookbehind和lookahead的正则表达式拆分字符串

  8. 8

    如何在javascript正则表达式中不选择lookbehind单词

  9. 9

    使用Java进行正则表达式Lookahead和Lookbehind

  10. 10

    LookBehind 正则表达式的语法

  11. 11

    如何使用正则表达式C ++?

  12. 12

    如何正则表达式匹配a / b / c ...?

  13. 13

    如何在C ++中注释正则表达式?

  14. 14

    使用C#查找日期的正则表达式

  15. 15

    使用正则表达式C#验证密码

  16. 16

    使用正则表达式时C ++程序崩溃

  17. 17

    使用C ++正则表达式,结果太慢

  18. 18

    在C中使用POSIX正则表达式

  19. 19

    在C中使用正则表达式

  20. 20

    正则表达式,使用C#查找日期

  21. 21

    使用C ++正则表达式和太慢的结果

  22. 22

    使用变量n正则表达式c#

  23. 23

    (C#正则表达式)如何使用正则表达式使单词边界适用于括号?

  24. 24

    如何在C ++中对多个正则表达式使用正则表达式“分组”?

  25. 25

    无法使用PCRE表达式的C ++正则表达式?

  26. 26

    在C ++中直接在表达式中使用正则表达式捕获

  27. 27

    在C ++中直接在表达式中使用正则表达式捕获

  28. 28

    在C#中使用正则表达式(正则表达式)从字符串获取值

  29. 29

    Perl正则表达式查找打包结构的名称,而无需使用可变长度的lookbehind?

热门标签

归档