¿Hay una manera mejor que esta para convertir una MatchCollection en una matriz de cadenas?
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;
}
PD: mc.CopyTo(strArray,0)
lanza una excepción:
Al menos un elemento de la matriz de origen no se pudo convertir en el tipo de matriz de destino.
OfType<Match>()
para esto en lugar deCast<Match>()
... Por otra parte, el resultado sería el mismo.Match
, por lo que no es necesario volver a comprobarlo en tiempo de ejecución.Cast
tiene más sentido.OfType<>
resulta ser un poco más rápido.MatchCollection
en astring[]
, ya que es paraMatch.ToString()
. Es bastante obvio que el tipo final que se necesita en muchosRegex
usos sería una cadena, por lo que debería haber sido fácil de convertir.La respuesta de Dave Bish es buena y funciona correctamente.
Vale la pena señalar, aunque reemplazar
Cast<Match>()
conOfType<Match>()
acelerará las cosas.El código se convertiría en:
var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b") .OfType<Match>() .Select(m => m.Groups[0].Value) .ToArray();
El resultado es exactamente el mismo (y aborda el problema de OP exactamente de la misma manera) pero para cadenas grandes es más rápido.
Código de prueba:
// 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()); }
El resultado es el siguiente:
OfType: 6540 Cast: 8743
Por lo tanto, para cadenas muy largas, Cast () es más lento.
fuente
Ejecuté exactamente el mismo punto de referencia que Alex ha publicado y descubrí que a veces
Cast
era más rápido y a vecesOfType
más rápido, pero la diferencia entre ambos era insignificante. Sin embargo, aunque feo, el ciclo for es consistentemente más rápido que los otros dos.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();
Resultados:
OfType: 3462 Cast: 3499 For: 2650
fuente
También se podría hacer uso de este método de extensión para lidiar con la molestia de
MatchCollection
no ser genérico. No es que sea un gran problema, pero es casi seguro que esto sea más eficaz queOfType
oCast
, porque es solo enumerar, lo que ambos también tienen que hacer.(Nota al margen: me pregunto si sería posible que el equipo de .NET
MatchCollection
heredara versiones genéricas deICollection
yIEnumerable
en el futuro. Entonces no necesitaríamos este paso adicional para tener disponibles transformaciones LINQ de inmediato).public static IEnumerable<Match> ToEnumerable(this MatchCollection mc) { if (mc != null) { foreach (Match m in mc) yield return m; } }
fuente
Considere el siguiente código ...
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();
fuente