【问题标题】:.Net Regex Lookahead Group with \Z (end of line) exception.Net Regex Lookahead Group with \Z(行尾)异常
【发布时间】:2015-07-29 13:51:51
【问题描述】:

我想我在 .NET Regex 引擎中发现了一个错误,并想知道是否有其他人遇到过它,或者它是否是某种预期的行为。

当匹配输入的结尾 character 断言 \Z 内的一组替代品 [] 内的前瞻组 (?=) 如在此示例表达式中,当它是已创建。

Regex test = new Regex(@"(?=[\Z])");

返回的异常是parsing "(?=[\Z])" - Unrecognized escape sequence \Z.

然而,正则表达式 [\Z] 可以工作(?=\Z) 也是如此

解决方法很简单,将(?=[]|\Z) 与替代组中所需的任何其他替代字符一起使用,但这仍然很奇怪。

编辑:我认为我的原始测试中一定有错字,因为正如 nhahtdh 指出的那样,上述模式实际上确实引发了异常。

使用 C# 在 .NET 4.5 中测试

【问题讨论】:

    标签: .net regex c#-4.0


    【解决方案1】:

    我不知道您为什么声称 @"[\Z]" 有效,但根据我对 ideone(目前在 .NET 4.0.30319.17020 上运行)的测试,它会引发与 @"(?=[\Z])" 相同的异常:

    System.ArgumentException: parsing '[\Z]' - Unrecognized escape sequence Z.
      at System.Text.RegularExpressions.RegexParser.ScanCharEscape () [0x00000] in <filename unknown>:0 
      at System.Text.RegularExpressions.RegexParser.ScanCharClass (Boolean caseInsensitive, Boolean scanOnly) [0x00000] in <filename unknown>:0 
      [...]
    

    顺便说一句,(?=[]|\Z) 也会抛出异常,因为它尝试解析由]| 组成的字符类并遇到无效的转义序列\Z

    检查RegexParser.ScanCharEscape 的代码,除了ECMAScript 模式(!UseOptionE()),如果遇到\ 后跟一个不构成已知转义序列的单词字符(注意在.NET 中,单词字符不仅限于A-Za-z0-9_,还包括Unicode中的其他单词字符。

                default:
                    if (!UseOptionE() && RegexCharClass.IsWordChar(ch))
                        throw MakeException(SR.Format(SR.UnrecognizedEscape, ch.ToString()));
                    return ch;
    

    这可能是一个设计决定,当人们转向更新版本的 .NET 框架时,允许将来扩展转义语法而不破坏现有代码库。 Java 在其Pattern 类中也遵循相同的设计原则,但它只会为A-Za-z 的无法识别的转义序列抛出异常。而 JavaScript/ECMAScript 则没有这样的限制,它将无法识别的转义序列解释为 \ 之后的字符。

    回到问题中的问题,注意\Z 是输入结束断言,即它匹配空字符串。断言不是字符,因此将其放在字符类中是没有意义的。如果您想在字符类中指定它,请使用交替 |

    【讨论】:

    • 啊,这很有道理,谢谢。我最初的困惑部分是由于我之前的测试给了我一个误报并导致我相信[\Z] 是有效的,而正如你所指出和解释的那样,它不是。
    【解决方案2】:

    你误解了\Z 是什么...因为它是一个模式 anchor转义并且不是一个实际的角色;因此,当尝试在 character 集 ([ ]) 中使用它时,该异常是有效的。

    它可以用来匹配\n,只要\n存在于数据的末尾,但它不是\n字符。

    引用 MSDN (Anchors in Regular Expressions):

    \Z 锚指定匹配必须出现在 输入字符串,或在输入字符串末尾的 \n 之前。这是 与 $ 锚相同,除了 \Z 忽略 RegexOptions.Multiline 选项。因此,在多行字符串中,它 只能匹配最后一行的结尾,或者\n之前的最后一行。

    注意 \Z 匹配 \n 但不匹配 \r\n(CR/LF 字符 组合)。要匹配 CR/LF,请在正则表达式中包含 \r?\Z 模式。

    【讨论】:

    • 我知道 \Z 是一个长度为零的锚,尽管我意识到我确实在问题中称它为一个字符。哎呀。
    猜你喜欢
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-13
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多