有人可以为我打破这个lambda表达吗?

时间:2013-05-21 19:01:56

标签: c# .net regex string

我正在查看来自Token Replacement and Identification的解决方案:

string result = Regex.Replace(
    text,
    @"\[%RC:(\d+)%\]",
    match => dict[int.Parse(match.Groups[1].Value)]);

我不明白MatchEvaluator是如何重载的。

我理解一些lambda表达式。它接受输入match,然后从字典中查找一个整数?

match的价值来自哪里?从match => dict[int.Parse(match.Groups[1].Value)]);返回的值在哪里?

编辑:有人提到Delegate。令人惊讶的是,在CS大学三年后,我没有遇到过这个学期。什么是Delegate以及在这种特定情况下它做了什么?

上次修改: 我尝试使用以下代码编写自己的委托 我的令牌的格式为[@someTokenName]

public void CreateScript(Dictionary<string,string> dictionary, string path)
    {
        //used in the regex to identify the string to replace
        var pattern = @"\[@[0-9a-fA-F]+\]";
        //read in the file found at the path
        var lines = File.ReadAllLines(path);
        int lineCounter = 0;
        foreach (string line in lines)
        {
            line = Regex.Replace(line, pattern, match => dictionary.TryGetValue((match.Groups[0].Value)));
        }

但我一直得到一个`无法将lambda表达式转换为'int'类型,因为它不是委托类型。我写的这行和解决方案中的一行有什么区别?

4 个答案:

答案 0 :(得分:58)

这是一个与lambda匹配的正则表达式,所以比普通的旧lambda复杂一点。我们走了:

假设:

String result = Regex.Replace(
    text,
    @"\[%RC:(\d+)%\]",
    match => dict[int.Parse(match.Groups[1].Value)]);

(1)text - 我们正在搜索的文本。

(2)@"\[%RC:(\d+)%\]" - 意味着找到任何看起来像“[%RC:{number}%]”的内容,其中{number}显然是某个数字(因为\d表示“一个数字” “,\d+表示”一个或多个连续的数字“)。另请注意,{number}\d+( )包围,与(\d+)一样。这很重要,因为这意味着该数字是一个“组”,这与我们下面的解释有关。组是从正则表达式中提取“有用”部分的一种方式。也就是说,我们不希望整个匹配,只是数字值

(3)当找到匹配项时,它会执行以下操作:match => dict[int.Parse(match.Groups[1].Value)]);

让我们从这部分开始:match => ...,它实际上与:

相同
public String MatchEval(Match match)
{

}

请记住,lambda表达式本质上只是常规函数的简写(除了编译器推断出match的类型,它的返回类型基于它所代表的委托 - 这里是 MatchEvaluator - 稍等一下)。这里,输入match作为输入传递给lambda表达式。然后你有=>开始功能体,类似于我们在{ }函数中看到的MatchEval。因此,每次找到匹配项时,都会运行与此块等效的代码:

public String MatchEval(Match match)
{
    // Here we grab the value from group (1) (the number in parentasis from our Regex)
    return dict[int.Parse(match.Groups[1].Value)];
}

简而言之,请记住lambda只是函数的简写符号。如果您查看Regex.Replace的文档,您会看到lambda代表MatchEvaluator,其定义为:

public delegate string MatchEvaluator(Match match);

与我们上面的函数扩展排列在一起。事实上,你可以简单地写:

String result = Regex.Replace(
    text,
    @"\[%RC:(\d+)%\]",
    MatchEval);

(假设dict可以从一个单独的方法访问)并且该函数将起到同样的作用,证明lambda只是一个完整函数的较短符号。

修改 至于你的问题的第二部分,“什么是委托”,委托基本上解决了这个问题:“我不知道我想用什么功能,但我知道它有什么标志”。考虑:

// This allows us to point to a math function with this signature,
// namely, takes two Int32 inputs, and returns an Int32.
public static delegate Int32 MathDelegate(Int32 lhs, Int32 rhs);

public static Int32 Add(Int32 lhs, Int32 rhs)
{
    return lhs + rhs;
}

// Note the variable names aren't important, just their TYPE
public static Int32 Subtract(Int32 a, Int32 b)
{
    return a - b;
}

static void Main()
{
    // We can use a delegate to point to a "real" function
    MathDelegate mathPerformer = Add;

    Console.WriteLine(mathPerformer(2, 3)); // Output : 5

    // Now let's point to "Subtract"
    mathPerformer = Subtract;

    Console.WriteLine(mathPerformer(2, 3)); // Output : -1

    Console.ReadLine();
}

如果在程序运行之前您不知道要使用哪种特定算法或处理技术,这将非常有用。委托让我们选择我们想要指向的函数,然后我们可以在程序运行时执行它。

这一切与上面的lambda讨论有关的方式是MatchEvaluator不知道如何处理它在字符串中查找时发现的每个匹配项。相反,通过为它提供lambda /函数,您可以告诉它在找到匹配项时要使用的算法。基本上,委托对于在运行时确定您希望如何执行某些操作非常有用。

修改: 如果要扩展lambda表达式以包含多个“行”代码,也可以使用代码块。考虑:

String result = Regex.Replace(
    text,
    @"\[%RC:(\d+)%\]",
    match => { 
       return dict[int.Parse(match.Groups[1].Value)]
    });

你会注意到这里有两件不同的东西。 (1)我们的=>后跟{ },后者允许我们输入多行代码。因此,编译器不知道哪个值是返回值,因此无法推断返回类型是什么。因此,(2)我们插入一个显式return命令来指示哪个值是应该返回的值。

通过这个简单的代码库,我们可以做类似的事情:

String result = Regex.Replace(
    text,
    @"\[%RC:(\d+)%\]",
    match => { 
       // This does the same thing, but with more lines of code.
       // Of course, you could get way more fancy with it as well.
       String numericValueAsString = match.Groups[1].Value;
       Int32 numericValue = Int32.Parse(numericValueAsString);
       String dictionaryValue = dict[numericValue];

       // Same as above
       return dictionaryValue;
    });

答案 1 :(得分:7)

想象:

string result = Regex.Replace(
text,
@"\[%RC:(\d+)%\]",
lambda);

//public delegate string MatchEvaluator(Match match)
string lambda(Match match) {
   return dict[int.Parse(match.Groups[1].Value)]); 
}

lambda表达式与MatchEvaluator的类型相同:match的值来自正则表达式(就像lambda表达式被定义为常规委托)和lambda表达式的值退货再次分配给result,就像它被定义为常规代理一样。

答案 2 :(得分:5)

用简单的英语:

对于与表达式匹配的所有组,使用索引值为1的组,将值解析为int并将其用作索引器/键从{{1}中提取值} dictionary调用object作为替换新值。

lambda只是一个匿名函数,它使用match作为参数并在参数的上下文中执行一个body。

答案 3 :(得分:3)

lambda只是定义了一个匿名函数。该函数传递给Replace方法(在本例中)。然后Replace可以使用该方法执行它想要的任何内容。您需要检查该特定方法的文档,以了解它如何使用提供的委托;你需要依靠它来告诉你参数的来源,它对返回值的作用等等。

该方法的MSDN页面指出,作为该参数的描述:

  

一种自定义方法,用于检查每个匹配并返回原始匹配字符串或替换字符串。

所以我们知道,对于找到的每个匹配,它将调用此方法,传递代表它找到的匹配项的Match对象作为参数。然后,它将使用string返回值(我知道它是一个字符串,因为definition of that delegate表明如此)该方法替换找到的匹配项。