Czy istnieje lepszy sposób niż ten, aby przekonwertować MatchCollection na tablicę ciągów?
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)
zgłasza wyjątek:
Co najmniej jeden element w tablicy źródłowej nie mógł zostać rzutowany na typ tablicy docelowej.
OfType<Match>()
tego zamiastCast<Match>()
... Z drugiej strony, wynik byłby taki sam.Match
, więc nie ma potrzeby sprawdzania tego ponownie w czasie wykonywania.Cast
ma więcej sensu.OfType<>
okazuje się być nieco szybszy.MatchCollection
w astring[]
, tak jak to jest w przypadkuMatch.ToString()
. Jest całkiem oczywiste, że ostatecznym typem potrzebnym w wieluRegex
zastosowaniach byłby ciąg, więc konwersja powinna być łatwa.Odpowiedź Dave'a Bisha jest dobra i działa poprawnie.
Warto zauważyć, chociaż zastąpienie
Cast<Match>()
goOfType<Match>()
przyspieszy.Kod stał się:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b") .OfType<Match>() .Select(m => m.Groups[0].Value) .ToArray();
Wynik jest dokładnie taki sam (i rozwiązuje problem OP dokładnie w ten sam sposób), ale w przypadku dużych ciągów jest szybszy.
Kod testowy:
// 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()); }
Wynik jest następujący:
OfType: 6540 Cast: 8743
Dlatego w przypadku bardzo długich ciągów Cast () jest wolniejsze.
źródło
Przeprowadziłem dokładnie ten sam test porównawczy, który opublikował Alex i stwierdziłem, że czasami
Cast
był szybszy, a czasamiOfType
szybszy, ale różnica między nimi była nieistotna. Jednak, choć brzydka, pętla for jest konsekwentnie szybsza niż obie pozostałe dwie.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();
Wyniki:
OfType: 3462 Cast: 3499 For: 2650
źródło
Można również skorzystać z tej metody rozszerzenia, aby poradzić sobie z irytacją wynikającą z
MatchCollection
braku bycia ogólnym. Nie żeby to była wielka sprawa, ale prawie na pewno jest to bardziej wydajne niżOfType
lubCast
, ponieważ to tylko wyliczenie, co obaj też muszą zrobić.(Nota boczna: zastanawiam się, czy zespół .NET mógłby
MatchCollection
dziedziczyć generyczne wersje programuICollection
iwIEnumerable
przyszłości? Wtedy nie potrzebowalibyśmy tego dodatkowego kroku, aby natychmiast mieć dostępne transformacje LINQ).public static IEnumerable<Match> ToEnumerable(this MatchCollection mc) { if (mc != null) { foreach (Match m in mc) yield return m; } }
źródło
Rozważ następujący kod ...
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();
źródło