Преобразование коллекции 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 54

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