Gibt es eine bessere Möglichkeit, eine MatchCollection in ein String-Array zu konvertieren?
MatchCollection mc = Regex.Matches(strText, @"\b[A-Za-z-']+\b");
string[] strArray = new string[mc.Count];
for (int i = 0; i < mc.Count;i++ )
{
strArray[i] = mc[i].Groups[0].Value;
}
PS: mc.CopyTo(strArray,0)
löst eine Ausnahme aus:
Mindestens ein Element im Quellarray konnte nicht auf den Zielarraytyp herabgesetzt werden.
OfType<Match>()
anstattCast<Match>()
... Andererseits wäre das Ergebnis das gleiche.Match
, sodass Sie es zur Laufzeit nicht erneut überprüfen müssen.Cast
macht mehr Sinn.OfType<>
sich als etwas schneller herausstellt.MatchCollection
in a zu verwandelnstring[]
, wie es istMatch.ToString()
. Es ist ziemlich offensichtlich, dass der endgültige Typ, der für vieleRegex
Anwendungen benötigt wird, eine Zeichenfolge ist, daher sollte die Konvertierung einfach sein.Dave Bishs Antwort ist gut und funktioniert richtig.
Es ist erwähnenswert, obwohl das Ersetzen
Cast<Match>()
durchOfType<Match>()
die Dinge beschleunigt.Code wird werden:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b") .OfType<Match>() .Select(m => m.Groups[0].Value) .ToArray();
Das Ergebnis ist genau das gleiche (und behandelt das Problem von OP genauso), aber für große Zeichenfolgen ist es schneller.
Testcode:
// put it in a console application static void Test() { Stopwatch sw = new Stopwatch(); StringBuilder sb = new StringBuilder(); string strText = "this will become a very long string after my code has done appending it to the stringbuilder "; Enumerable.Range(1, 100000).ToList().ForEach(i => sb.Append(strText)); strText = sb.ToString(); sw.Start(); var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b") .OfType<Match>() .Select(m => m.Groups[0].Value) .ToArray(); sw.Stop(); Console.WriteLine("OfType: " + sw.ElapsedMilliseconds.ToString()); sw.Reset(); sw.Start(); var arr2 = Regex.Matches(strText, @"\b[A-Za-z-']+\b") .Cast<Match>() .Select(m => m.Groups[0].Value) .ToArray(); sw.Stop(); Console.WriteLine("Cast: " + sw.ElapsedMilliseconds.ToString()); }
Ausgabe folgt:
OfType: 6540 Cast: 8743
Bei sehr langen Saiten ist Cast () daher langsamer.
quelle
Ich habe genau den gleichen Benchmark durchgeführt, den Alex veröffentlicht hat, und festgestellt, dass er manchmal
Cast
schneller und manchmalOfType
schneller war, aber der Unterschied zwischen beiden war vernachlässigbar. Obwohl hässlich, ist die for-Schleife durchweg schneller als die beiden anderen.Stopwatch sw = new Stopwatch(); StringBuilder sb = new StringBuilder(); string strText = "this will become a very long string after my code has done appending it to the stringbuilder "; Enumerable.Range(1, 100000).ToList().ForEach(i => sb.Append(strText)); strText = sb.ToString(); //First two benchmarks sw.Start(); MatchCollection mc = Regex.Matches(strText, @"\b[A-Za-z-']+\b"); var matches = new string[mc.Count]; for (int i = 0; i < matches.Length; i++) { matches[i] = mc[i].ToString(); } sw.Stop();
Ergebnisse:
OfType: 3462 Cast: 3499 For: 2650
quelle
Man könnte diese Erweiterungsmethode auch verwenden, um mit dem Ärger umzugehen,
MatchCollection
nicht generisch zu sein. Nicht, dass es eine große Sache wäre, aber dies ist mit ziemlicher Sicherheit performanter alsOfType
oderCast
, weil es nur eine Aufzählung ist, was beide auch tun müssen.(Randnotiz: Ich frage mich, ob es dem .NET-Team möglich sein würde,
MatchCollection
generische Versionen vonICollection
undIEnumerable
in Zukunft zu erben . Dann würden wir diesen zusätzlichen Schritt nicht benötigen, um sofort LINQ-Transformationen verfügbar zu haben.)public static IEnumerable<Match> ToEnumerable(this MatchCollection mc) { if (mc != null) { foreach (Match m in mc) yield return m; } }
quelle
Betrachten Sie den folgenden Code ...
var emailAddress = "[email protected]; [email protected]; [email protected]"; List<string> emails = new List<string>(); emails = Regex.Matches(emailAddress, @"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})") .Cast<Match>() .Select(m => m.Groups[0].Value) .ToList();
quelle