正则表达式 - C#的行为与Perl / Python不同

时间:2011-08-31 09:31:58

标签: c# regex

在Python下:

ttsiod@elrond:~$ python
>>> import re
>>> a='This is a test'
>>> re.sub(r'(.*)', 'George', a)
'George'

在Perl下:

ttsiod@elrond:~$ perl
$a="This is a test";
$a=~s/(.*)/George/;
print $a;
(Ctrl-D)

George

在C#下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;

namespace IsThisACsharpBug
{
  class Program
  {
    static void Main(string[] args)
    {
        var matchPattern = "(.*)";
        var replacePattern = "George";
        var newValue = Regex.Replace("This is nice", matchPattern, replacePattern);
        Console.WriteLine(newValue);
    }
  }
}

不幸的是,C#打印:

$ csc regexp.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.5420
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

$ ./regexp.exe 
GeorgeGeorge

这是C#正则表达式库中的错误吗?为什么它会打印“George”两次,当Perl和Python只打印一次?

4 个答案:

答案 0 :(得分:5)

在你的例子中,差异似乎在于'replace'函数的语义,而不是在正则表达式处理本身。

.net正在进行“全局”替换,即它正在替换所有匹配,而不仅仅是第一场比赛。

Perl中的全局替换

注意= ~s行末尾的小'g'

$a="This is a test";
$a=~s/(.*)/George/g;
print $a;

产生

GeorgeGeorge

在.NET中单个替换

var re = new Regex("(.*)");
var replacePattern = "George";
var newValue = re.Replace("This is nice", replacePattern, 1) ;
Console.WriteLine(newValue);

产生

George

因为它在第一次更换后停止。

答案 1 :(得分:2)

我不清楚它是否是一个错误,但是如果你将.*更改为.+它会做你想要的。我怀疑这是(.*)匹配一个令人困惑的空字符串的事实。

这由以下代码支持:

using System;
using System.Text.RegularExpressions;

class Test
{
    static void Main()
    {
        var match = Regex.Match("abc", "(.*)");
        while (match.Success)
        {
            Console.WriteLine(match.Length);
            match = match.NextMatch();
        }
    }
}

打印出3然后打印0.将图案更改为"(.+)"会使其打印出来。

需要注意的一点是,这与C#作为一种语言无关 - 只有.NET标准库。值得区分语言和库 - 例如,如果您使用F#,VB,C ++ / CLI等.NET标准库,您将获得完全相同的行为。

答案 2 :(得分:2)

""的替换为"George".*匹配""

"This is a start" == "This is a start" + "" 

因此正则表达式匹配"This is a start"并将其替换为"George",现在它的“光标”位于字符串的末尾,在那里他再次尝试匹配剩余的字符串({{1} })与模式。他有一场比赛,所以他增加了第二个""。我不知道这是否正确。

我将补充说,Javascript引擎似乎在IE和Chrome下执行相同的操作(在此处测试:http://www.regular-expressions.info/javascriptexample.html)。

答案 3 :(得分:2)

  

这是C#

正则表达式库中的错误吗?

也许,但这并没有真正回答你的问题:

  

正则表达式 - C#的行为与Perl / Python不同

不同的正则表达式引擎和实现的行为方式不同。有时这是显式的(并且包括支持不同的正则表达式元素和语法:例如,使用\(\)进行分组而不是使用反斜杠进行分组的普通括号。)

Mastering Regular Expressions(Jeffrey EF Friedl,O'Reilly)花了很多时间来解释这些差异(除了非确定性有限自动机(NFA)和确定性有限自动机(DFA)之间的更基本差异之外)方法)。

PS。正如其他人注意.*匹配空字符串,因此首先匹配并替换输入字符串的“all”,然后匹配并替换输入末尾的空字符串。如果你想匹配整个但可能是空的输入包括开头和结尾的锚点:^(.*)$