.NET Regex点字符匹配回车符?

时间:2010-02-17 16:00:29

标签: .net regex

我用过的每一种正则表达式都有“。”字符匹配除了新行(\ r或\ n)之外的所有内容...当然,除非您启用单行标记。

所以,当我尝试以下C#代码时,我感到震惊:

Regex rgx = new Regex(".");
if (rgx.Match("\r\n").Success)
  MessageBox.Show("There is something rotten in the state of Redmond!");

它显示了这条消息。为了确保我不会疯狂,我尝试了以下JavaScript代码:

if (/./.test("\r\n"))
  alert("Something's wrong with JavaScript too.");

JavaScript没有显示消息,这意味着它的工作正常。

显然,“。” .NET中的字符与“\ r”字符匹配。我检查了documentation以查看是否提及了它:

  

通配符:匹配任何单个字符   除了\ n。

哇...因为什么样的正则表达式永远让点匹配回车?您会认为.NET的行为与其他所有正则表达式一样......特别是因为它在Windows环境中使用“\ r \ n”作为行分隔符。

我是否可以启用任何标记/设置以使其像其他正则表达式一样工作?是否有任何替代解决方案不涉及用.替换所有[^\r\n]个字符?

5 个答案:

答案 0 :(得分:16)

在编写Regex Hero时遇到了同样的问题。这有点奇怪。我在博客上发表了关于here的问题。这导致我向测试人员添加了一个功能来启用/禁用CRLF。无论如何,出于某种原因,Microsoft选择使用\ n(换行符)来标记行结尾。

(更新)原因必须与此相关:

  

Microsoft .NET Framework常规   表达式包含最多   其他常规的流行功能   表达式实现,如   那些在Perl和awk。 旨在成为   兼容Perl 5常规   表达式,.NET Framework常规   表达式包括尚未提供的功能   在其他实现中看到,例如   从右到左的匹配和即时   汇编。   http://msdn.microsoft.com/en-us/library/hs600312.aspx

正如伊戈尔所说,Perl也有同样的行为。

现在,单线和多线RegexOptions会根据点和换行符更改行为。您可以启用Singleline RegexOption,以使点与换行匹配。并且您可以启用Multiline RegexOption,以便^和$标记每一行的开头和结尾(用换行符表示)。但是你不能改变点(。)运算符的固有行为来匹配除\ r \ n。

之外的所有内容

答案 1 :(得分:3)

我认为这里的要点是点应该匹配任何不是行分隔符的东西,而\r是行分隔符。 Perl只能识别\n,因为它(正如其他人指出的那样)植根于Unix世界,因为它是大多数其他语言中正则表达式的灵感来源。

(但我注意到在Perl 6正则表达式(或规则,使用它们的正式名称)中,/\n/匹配Unicode识别为行分隔符的任何内容,包括\r\n序列的两个字符。)

.NET诞生于Unicode时代;它应该识别所有 Unicode认可的行分隔符,包括\r(较旧的Mac风格)和\r\n(某些网络协议以及Windows使用)。在Java中考虑这个例子:

String s = "fee\nfie\r\nfoe\rfum";
Pattern p = Pattern.compile("(?m)^.+$");
Matcher m = p.matcher(s);
while (m.find())
{
  System.out.println(m.group().length());
}

结果:

3
3
3
3

.^$都可以正常使用所有三个行分隔符。现在在C#中尝试:

string s = "fee\nfie\r\nfoe\rfum";
Regex r = new Regex(@"(?m)^.+$");
foreach (Match m in r.Matches(s))
{
  Console.WriteLine(m.Value.Length);
}

结果:

3
4
7

这对其他人来说是否合适?这里我们有微软.NET框架内置的正则表达式风格,它甚至没有正确处理Windows标准行分隔符。它完全忽略了单独的\r,就像其他Unicode行分隔符一样。 .NET在Java之后几年出现,它的Unicode支持至少同样好,所以为什么他们选择坚持这一点呢?

答案 2 :(得分:2)

除单线模式外,.将匹配除\n以外的所有字符 正如您所注意到的,它与\r匹配。

我不知道为什么。

答案 3 :(得分:1)

正则表达式在Unix环境中具有实用(而非理论)的起源,其中LF是行终止符,然后它似乎完全适合。匹配除LF以外的所有东西。

这是一个单一的字符匹配,因此匹配CRLF太多而无法提问和匹配CR或LF可能会导致迁移正则表达式的跨平台问题。我认为使用\ s是一种更好的白空间匹配方法,并且会匹配CR和LF。

答案 4 :(得分:1)

好吧,我不认为“在雷德蒙德州有一些腐烂的东西!”,至少你的情景并不能证明这一点。但我认为这种行为不是一个错误,而是一个功能。为什么?仅仅因为Perl正则表达式具有相同的行为(我只是检查了它),我相信PHP的PCRE(Perl兼容正则表达式)的行为也是一样的。 MS只是使他们的Regex方法的行为与事实上的经典Perl方法相同。现在我的问题是:“JS王国出了什么问题?” :)