c# - \ d[0-9] से कम कुशल है




regex performance (4)

मैंने कल एक टिप्पणी पर एक टिप्पणी की जहां किसी ने [0-9] या \d बजाय नियमित अभिव्यक्ति में [0123456789] उपयोग किया था। मैंने कहा कि यह एक चरित्र सेट की तुलना में एक सीमा या अंक निर्दिष्ट करने के लिए शायद अधिक कुशल था।

मैंने आज परीक्षण करने का फैसला किया और मुझे आश्चर्य हुआ कि (सी # रेगेक्स इंजन में कम से कम) \d अन्य दो में से किसी भी से कम कुशल प्रतीत होता है जो बहुत अलग नहीं लगता है। यहां 5077 यादृच्छिक वर्णों के 10000 यादृच्छिक तारों से मेरा परीक्षण आउटपुट है जिसमें 5077 वास्तव में एक अंक है:

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

दो कारणों से मुझे आश्चर्य है:

  1. मैंने सोचा होगा कि सीमा सेट से अधिक कुशलतापूर्वक कार्यान्वित की जाएगी।
  2. मैं समझ नहीं पा रहा हूं कि क्यों [0-9] से भी बदतर है। [0-9] लिए बस shorthand की तुलना में \d लिए और अधिक है?

टेस्ट कोड यहां दिया गया है:

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

\ d सभी यूनिकोड की जांच करता है, जबकि [0-9] इन 10 अक्षरों तक सीमित है। यदि केवल 10 अंक हैं, तो आपको इसका उपयोग करना चाहिए। अन्य मैं कम लिखने के कारण \ d का उपयोग करने की सलाह देते हैं।


दस्तावेज़ों में इसे ध्यान में रखते हुए बाइटब्लैस्ट को क्रेडिट करें। बस रेगेक्स कन्स्ट्रक्टर बदल रहा है:

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

नए समय देता है:

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 कम कुशल होने जा रहा है क्योंकि तुलना के लिए परिवर्तित किया जाना है।

उदाहरण के लिए, अगर मैं रेगेक्स को आईपी पते ढूंढना चाहता था, तो मैं किसी भी अंक का प्रतिनिधित्व करने के लिए [0123456789] या यहां तक ​​कि [0-9] से भी अधिक \d करूंगा।

आम तौर पर मेरे रेगेक्स उपयोग में बोलते हुए, गति से अधिक महत्वपूर्ण होने पर कार्य करें।





performance