1341 votes

\d est moins efficace que [0-9]

J'ai fait un commentaire hier sur une réponse où quelqu'un avait utilisé [0123456789] dans une expression régulière plutôt que d' [0-9] ou \d. J'ai dit que c'était probablement plus efficace d'utiliser une fourchette ou un chiffre spécificateur qu'un jeu de caractères.

J'ai décidé de tester ça aujourd'hui et ont constaté à ma grande surprise (dans le C# regex moteur au moins) \d semble être moins efficace que les deux autres qui ne semblent pas différer beaucoup. Voici mon test de sortie de plus de 10000 chaînes aléatoires de 1000 caractères aléatoires avec 5077 réellement contenant un chiffre:

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

C'est une surprise pour moi pour deux raisons:

  1. J'aurais pensé que la plage serait mis en œuvre de manière beaucoup plus efficace que l'ensemble.
  2. Je ne comprends pas pourquoi \d est pire que d' [0-9]. Est-il plus \d que de simplement un raccourci pour [0-9]?

Voici le code de test:

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;
        }
    }
}

1659voto

Sina Iravanian Points 7246

\d vérifie tous Unicode chiffres, tandis que [0-9] est limité à 10 caractères. Par exemple, persan chiffres, ۱۲۳۴۵۶۷۸۹, sont un exemple de l'Unicode des chiffres qui correspondent aux \d, mais pas [0-9].

Vous pouvez générer une liste de tous ces caractères en utilisant le code suivant:

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());

Qui génère:

0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯୦୧୨୩୪୫୬୭୮୯௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮൯๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤༥༦༧༨༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙0123456789

284voto

weston Points 11882

Crédit à ByteBlast pour s'en rendre compte dans les docs. En changeant simplement la regex constructeur:

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

Donne de nouveaux horaires:

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

125voto

Ismet Alkan Points 2703

De Ne "\d" dans la regex moyenne un chiffre?:

[0-9] n'est pas équivalent à \d. [0-9] matchs 0123456789 personnages, alors que \d correspond [0-9] et d'autres chiffres, par exemple, l'Eastern chiffres arabes ٠١٢٣٤٥٦٧٨٩

21voto

Sebastian Godelet Points 1093

Un plus haut en réponse à partir de Sina Iravianian, voici une .NET version 4.5 (puisque seule cette version prend en charge les UTF16 de sortie, c.f. les trois premières lignes) de son code, à l'aide de la gamme complète de points de code Unicode. En raison de l'absence de soutien pour les plus Unicode avions, beaucoup de gens ne sont pas conscients de toujours vérifier et y compris la partie supérieure de l'Unicode des avions. Néanmoins, parfois, ils ne contiennent certains caractères importants.

public static void Main()
{
    var unicodeEncoding = new UnicodeEncoding(!BitConverter.IsLittleEndian, false);
    Console.InputEncoding = unicodeEncoding;
    Console.OutputEncoding = unicodeEncoding;

    var sb = new StringBuilder();
    for (var codePoint = 0; codePoint <= 0x10ffff; codePoint++)
    {
        var isSurrogateCodePoint = codePoint <= UInt16.MaxValue 
               && (  char.IsLowSurrogate((char) codePoint) 
                  || char.IsHighSurrogate((char) codePoint)
                  );

        if (isSurrogateCodePoint)
            continue;

        var codePointString = char.ConvertFromUtf32(codePoint);

        if (Regex.IsMatch(codePointString, @"\d"))
            sb.AppendFormat("{0} ", codePointString);
    }
    Console.WriteLine(sb.ToString());

    Console.ReadKey();
}

Ce qui donne le résultat suivant:

0 1 2 3 4 5 6 7 8 9 ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ߀ ߁ ߂ ߃ ߄ ߅ ߆ ߇ ߈ ߉ ० १ २ ३ ४ ५ ६ ७ ८ ९
০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯ ੦ ੧ ੨ ੩ ੪ ੫ ੬ ੭ ੮ ੯ ૦ ૧ ૨ ૩ ૪ ૫ ૬ ૭ ૮ ૯ ୦ ୧ ୨ ୩ ୪ ୫ ୬ ୭ ୮ ୯ ௦ ௧ ௨ ௩ ௪ ௫ ௬ ௭ ௮ ௯
౦ ౧ ౨ ౩ ౪ ౫ ౬ ౭ ౮ ౯ ೦ ೧ ೨ ೩ ೪ ೫ ೬ ೭ ೮ ೯ ൦ ൧ ൨ ൩ ൪ ൫ ൬ ൭ ൮ ൯
๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙ ໐ ໑ ໒ ໓ ໔ ໕ ໖ ໗ ໘ ໙ ༠ ༡ ༢ ༣ ༤ ༥ ༦ ༧ ༨ ༩ ၀ ၁ ၂ ၃ ၄ ၅ ၆ ၇ ၈ ၉ ႐ ႑ ႒ ႓ ႔ ႕ ႖ ႗ ႘ ႙
០ ១ ២ ៣ ៤ ៥ ៦ ៧ ៨ ៩ ᠐ ᠑ ᠒ ᠓ ᠔ ᠕ ᠖ ᠗ ᠘ ᠙ ᥆ ᥇ ᥈ ᥉ ᥊ ᥋ ᥌ ᥍ ᥎ ᥏ ᧐ ᧑ ᧒ ᧓ ᧔ ᧕ ᧖ ᧗ ᧘ ᧙ ᭐ ᭑ ᭒ ᭓ ᭔ ᭕ ᭖ ᭗ ᭘ ᭙ ᮰ ᮱ ᮲ ᮳ ᮴ ᮵ ᮶
᮷ ᮸ ᮹ ᱀ ᱁ ᱂ ᱃ ᱄ ᱅ ᱆ ᱇ ᱈ ᱉ ᱐ ᱑ ᱒ ᱓ ᱔ ᱕ ᱖ ᱗ ᱘ ᱙ ꘠ ꘡ ꘢ ꘣ ꘤ ꘥ ꘦ ꘧ ꘨ ꘩ ꣐ ꣑ ꣒ ꣓ ꣔ ꣕ ꣖ ꣗ ꣘ ꣙ ꤀ ꤁ ꤂ ꤃ ꤄
꤅ ꤆ ꤇ ꤈ ꤉ ꩐ ꩑ ꩒ ꩓ ꩔ ꩕ ꩖ ꩗ ꩘ ꩙ 0 1 2 3 4 5 6 7 8 9

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X