remarks - xml comments c#




\ d es menos eficiente que (4)

Ayer hice un comentario sobre una respuesta en la que alguien había usado [0123456789] en una expresión regular en lugar de [0-9] o \d . Dije que probablemente era más eficiente usar un especificador de rango o dígito que un conjunto de caracteres.

Decidí probarlo hoy y me sorprendió que (al menos en el motor de expresiones regulares C #) parece ser menos eficiente que cualquiera de los otros dos, que no parecen diferir mucho. Aquí está mi salida de prueba de más de 10000 cadenas aleatorias de 1000 caracteres aleatorios con 5077 que realmente contienen un dígito:

Regular expression \d           took 00:00:00.2141226 result: 5077/10000
Regular expression [0-9]        took 00:00:00.1357972 result: 5077/10000  63.42 % of first
Regular expression [0123456789] took 00:00:00.1388997 result: 5077/10000  64.87 % of first

Es una sorpresa para mí por dos razones:

  1. Pensé que el rango se implementaría de manera mucho más eficiente que el conjunto.
  2. No puedo entender por qué \d es peor que [0-9] . ¿Hay más de \d que simplemente taquigrafía para [0-9] ?

Aquí está el código de prueba:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace SO_RegexPerformance
{
    class Program
    {
        static void Main(string[] args)
        {
            var rand = new Random(1234);
            var strings = new List<string>();
            //10K random strings
            for (var i = 0; i < 10000; i++)
            {
                //Generate random string
                var sb = new StringBuilder();
                for (var c = 0; c < 1000; c++)
                {
                    //Add a-z randomly
                    sb.Append((char)('a' + rand.Next(26)));
                }
                //In roughly 50% of them, put a digit
                if (rand.Next(2) == 0)
                {
                    //Replace one character with a digit, 0-9
                    sb[rand.Next(sb.Length)] = (char)('0' + rand.Next(10));
                }
                strings.Add(sb.ToString());
            }

            var baseTime = testPerfomance(strings, @"\d");
            Console.WriteLine();
            var testTime = testPerfomance(strings, "[0-9]");
            Console.WriteLine("  {0:P2} of first", testTime.TotalMilliseconds / baseTime.TotalMilliseconds);
            testTime = testPerfomance(strings, "[0123456789]");
            Console.WriteLine("  {0:P2} of first", testTime.TotalMilliseconds / baseTime.TotalMilliseconds);
        }

        private static TimeSpan testPerfomance(List<string> strings, string regex)
        {
            var sw = new Stopwatch();

            int successes = 0;

            var rex = new Regex(regex);

            sw.Start();
            foreach (var str in strings)
            {
                if (rex.Match(str).Success)
                {
                    successes++;
                }
            }
            sw.Stop();

            Console.Write("Regex {0,-12} took {1} result: {2}/{3}", regex, sw.Elapsed, successes, strings.Count);

            return sw.Elapsed;
        }
    }
}

Desde ¿"\ d" en expresiones regulares significa un dígito? :

[0-9] no es equivalente a \d . [0-9] solo coincide con 0123456789 caracteres, mientras que \d coincide con [0-9] y otros caracteres de dígitos, por ejemplo, números arábigos orientales ٠١٢٣٤٥٦٧٨٩


Gracias a ByteBlast por darse cuenta de esto en los documentos. Solo cambiando el constructor regex:

var rex = new Regex(regex, RegexOptions.ECMAScript);

Da nuevos tiempos:

Regex \d           took 00:00:00.1355787 result: 5077/10000
Regex [0-9]        took 00:00:00.1360403 result: 5077/10000  100.34 % of first
Regex [0123456789] took 00:00:00.1362112 result: 5077/10000  100.47 % of first

\ d comprueba todos los Unicode, mientras que [0-9] está limitado a estos 10 caracteres. Si solo 10 dígitos, deberías usarlo. Otros recomiendo usar \ d , porque escribir menos.


\d comprueba todos los dígitos de Unicode, mientras que [0-9] está limitado a estos 10 caracteres. Por ejemplo, Persian dígitos Persian , ۱۲۳۴۵۶۷۸۹ , son un ejemplo de dígitos Unicode que coinciden con \d , pero no [0-9] .

Puede generar una lista de todos estos caracteres utilizando el siguiente código:

var sb = new StringBuilder();
for(UInt16 i = 0; i < UInt16.MaxValue; i++)
{
    string str = Convert.ToChar(i).ToString();
    if (Regex.IsMatch(str, @"\d"))
        sb.Append(str);
}
Console.WriteLine(sb.ToString());

Lo que genera:

0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८ ௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮൯๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤༥༦༧༨༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩ ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙







performance