Преобразование коллекции MatchCollection в массив строк
есть ли лучший способ, чем это, чтобы преобразовать MatchCollection в массив строк?
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;
}
П. С.: mc.CopyTo(strArray,0)
исключение:
по крайней мере один элемент в исходном массиве не может быть приведен к целевому типу массива.
5 ответов:
попробуй:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b") .Cast<Match>() .Select(m => m.Value) .ToArray();
ответ Дэйва Биша хорош и работает правильно.
стоит отметить, хотя, что замена
Cast<Match>()
СOfType<Match>()
ускорит процесс.код Волд стал:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b") .OfType<Match>() .Select(m => m.Groups[0].Value) .ToArray();
результат точно такой же (и решает проблему OP точно так же), но для огромных строк это быстрее.
тестовый код:
// 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()); }
выход образом:
OfType: 6540 Cast: 8743
на очень долго строки литой (), следовательно, является замедлившийся.
Я запустил тот же самый бенчмарк, что и Алекс, и обнаружил, что иногда
Cast
было быстрее и иногдаOfType
был быстрее, но разница между ними была незначительной. Однако, в то время как уродливый, цикл for последовательно быстрее, чем оба других двух.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();
результаты:
OfType: 3462 Cast: 3499 For: 2650
рассмотрим следующий код...
var emailAddress = "joe@sad.com; joe@happy.com; joe@elated.com"; 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();
Удачи!
можно использовать этот метод расширения, чтобы справиться с раздражением
MatchCollection
не универсальный. Не то чтобы это большое дело, но это почти наверняка более эффективно, чемOfType
илиCast
, потому что это просто перечисление, которое оба из них также должны сделать.(боковое Примечание: интересно, если бы это было возможно для команды .NET, чтобы сделать
MatchCollection
наследовать общие версииICollection
иIEnumerable
в будущем? Тогда нам не понадобится этот дополнительный шаг, чтобы немедленно есть LINQ преобразования доступны)public static IEnumerable<Match> ToEnumerable(this MatchCollection mc) { if (mc != null) { foreach (Match m in mc) yield return m; } }