Questa è un'espressione regolare abbinata a una lambda, quindi un po 'più complicata della normale lambda. Ecco come fare:
Data:
String result = Regex.Replace(
text,
@"\[%RC:(\d+)%\]",
match => dict[int.Parse(match.Groups[1].Value)]);
(1) il testo - il testo che stiamo cercando attraverso.
(2) @"\[%RC:(\d+)%\]"
- mezzi trovato nulla che assomiglia a "[% CR: {numero}%]" dove {number}
è ovviamente un certo numero (dal \d
significa "un numero", e \d+
significa "uno o più numeri in successione"). Si noti inoltre che lo {number}
o \d+
è circondato da ()
come in (\d+)
. Questo è importante perché significa che il numero è un "gruppo", che ha portato alla nostra spiegazione di seguito. I gruppi sono un modo per estrarre la parte "utile" da un'espressione regolare. Cioè, non vogliamo l'intera partita, solo il valore numero.
(3) Quando si trova una corrispondenza, esegue questo: match => dict[int.Parse(match.Groups[1].Value)]);
Partiamo da questa parte: match => ...
, che è effettivamente la stessa:
public String MatchEval(Match match)
{
}
ricordare che un'espressione lambda è essenzialmente solo una breve mano per una funzione regolare (tranne che il compilatore deduce il tipo per match
e il suo tipo di ritorno in base al delegato per cui è in piedi - qui un MatchEvaluator - di più su questo in un momento). Qui, l'input match
viene passato nell'espressione lambda come input. Quindi hai =>
che inizia il corpo della funzione simile a { }
che vediamo nella nostra funzione MatchEval
sopra. Di conseguenza, ogni volta che viene trovata una corrispondenza, il codice equivalente a questo blocco viene eseguito:
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)];
}
In breve, ricorda che un lambda è solo notazione abbreviata per una funzione. Se si guarda la documentazione per Regex.Replace, vedrai che il lambda è in piedi in un MatchEvaluator che è definita come:
public delegate string MatchEvaluator(Match match);
che si allinea con la nostra espansione funzione di cui sopra. In realtà, si potrebbe semplicemente scrivere:
String result = Regex.Replace(
text,
@"\[%RC:(\d+)%\]",
MatchEval);
(supponendo dict
era accessibile da un metodo separato) e la funzione funzionerebbe lo stesso dimostrando che un lambda è solo una notazione più breve per una funzione completa.
Edit: quanto riguarda la seconda parte della sua domanda, "Che cos'è un delegato", un delegato risolve essenzialmente il problema: "Non so quale funzione che voglio usare, ma so quello che firma esso ha". Considerate:
// 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();
}
Questo è utile quando non si sa cosa algoritmo specifico, o di tecnica di lavorazione che si desidera utilizzare fino il programma è già in esecuzione. Un delegato ci consente di scegliere a quale funzione puntare, e quindi possiamo eseguirlo mentre il programma è in esecuzione.
Il modo in cui tutto questo si riferisce alla discussione lambda di cui sopra, è che il MatchEvaluator
non sa come gestire ciascuna delle corrispondenze che trova man mano che scorre nella stringa. Invece, fornendogli una funzione lambda, gli stai dicendo quale algoritmo vuoi usare quando viene trovata una corrispondenza. Fondamentalmente un delegato è utile per determinare in fase di esecuzione come si desidera eseguire un'azione.
Edit: Se si desidera espandere le vostre espressioni lambda per includere più di una 'linea' di codice, è possibile utilizzare un blocco di codice pure. Considerare:
String result = Regex.Replace(
text,
@"\[%RC:(\d+)%\]",
match => {
return dict[int.Parse(match.Groups[1].Value)]
});
Qui noterete due cose diverse. (1) Il nostro =>
è ora seguito da { }
che ci consente di inserire più righe di codice. Di conseguenza, tuttavia, il compilatore non sa quale valore è il valore restituito e quindi non può dedurre quale sia il tipo restituito. Pertanto, (2) inseriamo un comando esplicito return
per indicare quale valore deve essere restituito.
Con questo semplice codice di base, potremmo fare qualcosa di simile:
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;
});
Un 'Delegate' è simile a un puntatore a funzione. IOW, è un riferimento a un metodo; ma tu determini in fase di esecuzione il metodo specifico a cui fa riferimento. Dai un'occhiata a http://msdn.microsoft.com/en-us/library/900fyy8e(v=vs.71).aspx – ThatBlairGuy
Che ha chiarito perfettamente le cose – Wusiji
Quindi, in primo luogo, il compilatore deve essere in grado di dedurre che il tuo L'espressione lambda corrisponde a "MatchEvaluator", il che significa che deve avere un "Match" come input e "String" come output. Tuttavia, 'dictionary.TryGetValue' restituisce un' Boolean' piuttosto che un 'String', quindi il compilatore ti urlerà perché i tipi restituiti non corrispondono. In questo caso dovresti semplicemente usare 'dictionary [match.Groups [0] .Value]'. Tuttavia, se vuoi essere elegante e verificare prima che il valore esista, scriverò un altro esempio in un momento. – sircodesalot