Может ли кто-то сломать это выражение лямбды для меня? - программирование
Подтвердить что ты не робот

Может ли кто-то сломать это выражение лямбды для меня?

Я смотрю на решение Замена и идентификация токена:

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

И я не понимаю, как была перегружена MatchEvaluator.

Я понимаю часть лямбда-выражения. Он принимает ввод match, а затем ищет целое число из словаря?

Но откуда взялось значение для match? и где значение, возвращаемое из match => dict[int.Parse(match.Groups[1].Value)]); go?

Изменить: некоторые из вас упоминали 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)));
        }

Но я продолжаю получать "Не могу преобразовать лямбда-выражение в тип" int ", потому что это не тип делегата. Какая разница между строкой, которую я написал, и той, что найдена в решении?

4b9b3361

Ответ 1

Это регулярное выражение, сопоставимое с лямбдой, поэтому немного сложнее, чем обычная старая лямбда. Здесь мы идем:

Дано:

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

(1) текст - текст, который мы просматриваем.

(2) @"\[%RC:(\d+)%\]" - означает найти все, что выглядит "[% RC: {число}%]", где {number}, очевидно, некоторое число (так как \d означает "число" и \d+ означает "одно или несколько номеров подряд" ). Также обратите внимание, что {number} или \d+ окружен ( ), как в (\d+). Это важно, потому что это означает, что число является "группой", что имеет отношение к нашему объяснению ниже. Группы - это способ извлечения "полезной" части из регулярного выражения. То есть, нам не нужен весь матч, просто значение числа.

(3) Когда он находит совпадение, он выполняет следующее: match => dict[int.Parse(match.Groups[1].Value)]);

Давайте начнем с этой части: match => ..., которая фактически будет такой же, как:

public String MatchEval(Match match)
{

}

помните, что выражение лямбда по существу является просто короткой рукой для регулярной функции (кроме того, что компилятор указывает тип для match и возвращает тип, основанный на делетете, для которого он стоит, - здесь MatchEvaluator - больше об этом в одно мгновение). Здесь вход match передается в лямбда-выражение в качестве входного сигнала. Тогда у вас есть =>, который начинает тело функции, аналогичное { }, которое мы видим в нашей функции 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)];
}

Короче говоря, помните, что лямбда - это просто сокращенная нотация для функции. Если вы посмотрите на документацию для Regex.Replace, вы увидите, что лямбда стоит за MatchEvaluator, который определяется как:

public delegate string MatchEvaluator(Match match);

что соответствует нашему расширению функции выше. Фактически, вы могли бы просто написать:

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

(предполагая, что dict был доступен из отдельного метода), и функция будет работать точно так же, доказывая, что лямбда - это всего лишь более короткая нотация для полной функции.

Edit: Что касается второй части вашего вопроса: "Что такое делегат", делегат существенно решает проблему: "Я не знаю, какую функцию я хочу использовать, но я знаю, какая подпись у нее есть". Рассмотрим:

// 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 point to "Subtract"
    mathPerformer = Subtract;

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

    Console.ReadLine();
}

Это полезно, когда вы не знаете, какой конкретный алгоритм или метод обработки вы хотите использовать до тех пор, пока программа не будет запущена. Делегат позволяет выбрать, какую функцию мы хотим указать, а затем мы можем выполнить его во время работы программы.

Способ, которым все это относится к рассмотренному выше лямбда-диску, заключается в том, что MatchEvaluator не знает, как обрабатывать каждое совпадение, которое оно находит, когда оно просматривает вашу строку. Вместо этого, предоставляя ему лямбда/функцию, вы говорите, какой алгоритм вы хотите использовать, когда найдено совпадение. В принципе делегат полезен для определения во время выполнения того, как вы хотите выполнить какое-либо действие.

Edit: Если вы хотите расширить свои лямбда-выражения, чтобы включить более одной строки кода, вы также можете использовать блок кода. Рассмотрим:

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;
    });

Ответ 2

Представьте себе:

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)]); 
}

Выражение лямбда имеет тот же тип, что и MatchEvaluator: значение для match происходит из регулярного выражения (точно так же, как если бы выражение лямбда было определено как обычный делегат), а значение, возвращаемое выражением лямбда, присваивается result, опять же, так же, как и если бы он был определен как обычный делегат.

Ответ 3

В простом английском:

Для всех групп, соответствующих выражению, используйте группу в значении индекса 1, проанализируйте значение как int и используйте его в качестве индексатора/ключа, чтобы вывести значение из dictionary object называемый dict для использования в качестве нового нового значения.

Лямбда - это просто анонимная функция, которая использует совпадение в качестве аргумента и выполняет тело в контексте аргумента.

Ответ 4

Лямбда просто определяет анонимную функцию. Эта функция передается методу Replace (в данном случае). Replace может делать все, что захочет, с помощью этого метода. Вам нужно будет проверить документацию для этого конкретного метода, чтобы увидеть, как он использует предоставленный делегат; вам нужно будет положиться на это, чтобы сообщить вам, откуда этот параметр, что он делает с возвращаемым значением и т.д.

Страница MSDN для этого метода указывает, как описание для этого параметра:

Пользовательский метод, который проверяет каждое совпадение и возвращает либо исходную согласованную строку, либо заменяющую строку.

Итак, мы знаем, что для каждого найденного совпадения он вызовет этот метод, передав объект Match, который представляет совпадение, которое он нашел в качестве параметра. Затем он будет использовать возвращаемое значение string (я знаю, что это строка, потому что определение этого делегата указывает) этого метода как то, что замените найденное совпадение на.