web-dev-qa-db-fra.com

Conversion d'un MatchCollection en tableau de chaînes

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.

68
Vil

Essayer:

var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
    .Cast<Match>()
    .Select(m => m.Value)
    .ToArray();
142
Dave Bish

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.

26
Alex

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
5
David DeMar

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;
    }
}
1
Nicholas Petersen

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!

0
gpmurthy