Existe-t-il un meilleur moyen que celui-ci pour convertir un MatchCollection en un tableau de chaînes?
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;
}
P.S .: mc.CopyTo(strArray,0)
lève une exception:
Au moins un élément du tableau source n'a pas pu être converti en type de tableau de destination.
Essayer:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
.Cast<Match>()
.Select(m => m.Value)
.ToArray();
La réponse de Dave Bish est bonne et fonctionne correctement.
Il convient de noter que le remplacement de Cast<Match>()
par OfType<Match>()
accélérera les choses.
Le code deviendra:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
.OfType<Match>()
.Select(m => m.Groups[0].Value)
.ToArray();
Le résultat est exactement le même (et traite le problème d'OP de la même manière) mais pour les chaînes énormes, c'est plus rapide.
Code de test:
// 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());
}
La sortie suit:
OfType: 6540
Cast: 8743
Pour très long cordes Cast () est donc plus lent.
J'ai exécuté exactement le même benchmark qu'Alex a publié et j'ai constaté que parfois Cast
était plus rapide et parfois OfType
était plus rapide, mais la différence entre les deux était négligeable. Cependant, bien que laide, la boucle for est toujours plus rapide que les deux autres.
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();
Résultats:
OfType: 3462
Cast: 3499
For: 2650
On pourrait également utiliser cette méthode d'extension pour faire face au désagrément de MatchCollection
qui n'est pas générique. Ce n'est pas un gros problème, mais c'est presque certainement plus performant que OfType
ou Cast
, car il s'agit simplement d'énumérer, ce que les deux doivent également faire.
(Remarque: je me demande s'il serait possible pour l'équipe .NET de faire en sorte que MatchCollection
hérite des versions génériques de ICollection
et IEnumerable
à l'avenir? besoin de cette étape supplémentaire pour disposer immédiatement de transformations LINQ).
public static IEnumerable<Match> ToEnumerable(this MatchCollection mc)
{
if (mc != null) {
foreach (Match m in mc)
yield return m;
}
}
Considérez le code suivant ...
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();
Bonne chance!