Ответ 1
Try:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
.Cast<Match>()
.Select(m => m.Value)
.ToArray();
Есть ли лучший способ конвертировать 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;
}
PS: mc.CopyTo(strArray,0)
выдает исключение:
По крайней мере, один элемент в исходном массиве не может быть приведен к типу целевого массива.
Try:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
.Cast<Match>()
.Select(m => m.Value)
.ToArray();
Ответ Дейва Биша хорош и работает правильно.
Стоит отметить, что замена Cast<Match>()
на OfType<Match>()
ускорит процесс.
Код wold станет:
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() поэтому медленнее.
Я запустил тот же тест, что и Алекс, и обнаружил, что иногда 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
Можно также использовать этот метод расширения, чтобы справиться с раздражением 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;
}
}
Рассмотрим следующий код...
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();
Удачи!