[d] [0-9] की तुलना में कम कुशल है


1246

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

मैंने आज उस परीक्षण का निर्णय लिया और मेरे आश्चर्य का पता चला कि (C # regex इंजन में कम से कम) \dअन्य दो की तुलना में कम कुशल प्रतीत होता है जो कि अधिक भिन्न नहीं लगते हैं। यहां मेरे परीक्षण का उत्पादन 1000 से अधिक यादृच्छिक वर्णों के साथ 50 यादृच्छिक वर्णों का 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. मैं समझ नहीं पा रहा हूं कि \dइससे भी बदतर क्यों है [0-9]। वहाँ के लिए \dबस आशुलिपि की तुलना में अधिक है [0-9]?

यहाँ परीक्षण कोड है:

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

178
शायद \dस्थानों से संबंधित है। Eg हिब्रू अंकों के लिए अक्षरों का उपयोग करता है।
बरमार

6

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

17
@ बरमेर हिब्रू अंकों के लिए सामान्य रूप से अक्षरों का उपयोग नहीं करते हैं, बल्कि उसी लैटिन अंक के अंक [0-9]। अक्षरों को अंकों के लिए प्रतिस्थापित किया जा सकता है, लेकिन यह एक दुर्लभ उपयोग है और विशेष शब्दों के लिए आरक्षित है। मैं रेगेक्स पार्सर से ג"י יורסי רירה ()" subst 23 के लिए एक विकल्प के रूप में) के साथ मेल खाने की उम्मीद नहीं करूंगा। इसके अलावा, जैसा कि सीना इरावनियन के जवाब में देखा जा सकता है, हिब्रू अक्षर \ d के लिए वैध मैचों के रूप में प्रकट नहीं होते हैं।
युवल एडम

7
जावा पैदावार के लिए पश्चिम की ओर कोडिंग कोड: - रेगेक्स \ d ने 00: 00: 00.043922 परिणाम: 4912/10000 - रेगेक्स [0-9] लिया 00: 00: 00.073658 परिणाम: 4912/10000 / 7 पहले का% - रेगेक्स [ पहले की 4912/10000 195%: 00: 0123456789] 00 ले लिया ००.०८५७९९ परिणाम
Lunchbox

जवाबों:


1565

\dसभी यूनिकोड अंकों की जाँच करता है, जबकि [0-9]ये 10 वर्णों तक सीमित है। उदाहरण के लिए, फ़ारसी अंक, ۱۲۳۴۵۶۷۸۹यूनिकोड अंकों का एक उदाहरण है, जिसका मिलान होता है \d, लेकिन नहीं [0-9]

आप निम्नलिखित कोड का उपयोग करके ऐसे सभी पात्रों की सूची तैयार कर सकते हैं:

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

जो उत्पन्न करता है:

012345678901234567890123456789߀߁߂߃߄߅߆߇߈߉012345678 9 01২345678901234567890123456789 ୦୧୨୩୪୫୬୭୮୯ 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ ᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙ ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙0123456789


121
: यहाँ अंक कि 0-9 नहीं हैं की एक पूरी सूची है fileformat.info/info/unicode/category/Nd/list.htm
रॉबर्ट मैककी

8
@ वेस्टन यूनिकोड में 16 बिट्स के साथ 17 प्लेन हैं। अधिकांश महत्वपूर्ण पात्र मूल विमान में हैं, लेकिन कुछ विशेष पात्र, जिनमें अधिकतर चीनी हैं, पूरक विमानों में हैं। C # में उन लोगों के साथ व्यवहार करना थोड़ा कष्टप्रद है।
कोडइन्चोस

9
@RobertMcKee: Nitpick: पूर्ण यूनिकोड वर्ण सेट वास्तव में 21 बिट (प्रत्येक 16 बिट के 17 विमान) है। लेकिन निश्चित रूप से एक 21-बिट-डेटाटाइप अव्यवहारिक है, इसलिए यदि आप पावर-ऑफ -2 डेटाटाइप का उपयोग करते हैं, तो यह सच है कि आपको 32 बिट की आवश्यकता है।
sleske

3
इस विकिपीडिया लेख के अनुसार , यूनिकोड कंसोर्टियम ने कहा है कि 1,114,112 कोड पॉइंट्स (0 से 0x010FFFF) की सीमा कभी नहीं बदली जाएगी। यह unicode.org से लिंक करता है, लेकिन मुझे वहां यह कथन नहीं मिला (मुझे शायद यह याद नहीं था)।
कीथ थॉम्पसन

14
इसे कभी नहीं बदला जाएगा - जब तक कि उन्हें इसे बदलने की आवश्यकता न हो।
रॉबर्ट मैककी

271

डॉक्स में इसे नोट करने के लिए बाइटब्लास्ट को क्रेडिट। रेगेक्स कंस्ट्रक्टर को बस बदलना:

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

11
क्या करता RegexOptions.ECMAScriptहै?
लौरेंत

7
से नियमित अभिव्यक्ति विकल्प : "अभिव्यक्ति के लिए ECMAScript अनुरूप व्यवहार सक्षम करें।"
क्रिसकॉक

28
@ 0xFE: काफी नहीं। यूनीकोड ​​एस्केप अभी भी ECMAScript( \u1234) में मान्य हैं । यह "सिर्फ" शॉर्टहैंड चरित्र वर्ग हैं जो अर्थ बदलते हैं (जैसे \d) और यूनिकोड संपत्ति / स्क्रिप्ट शॉर्टहैंड जो चले जाते हैं (जैसे \p{N})।
टिम पीटरज़

9
यह "क्यों" भाग का जवाब नहीं है। यह "लक्षणों को ठीक करना" उत्तर है। फिर भी बहुमूल्य जानकारी।
usr

आम तौर पर, Regrex यूनिकोड मिलान का समर्थन करता है। लेकिन ECMAScript नहीं है। इसलिए, जब RegexOptions.ECMAScript का उपयोग किया जाता है, तो यह केवल एएससीआई यानी 0-9 से मेल खाता है।
lzlstyle

119

से करता है "\ घ" regex में अंक के क्या मतलब है? :

[0-9]के बराबर नहीं है \d[0-9]केवल 0123456789पात्रों से मेल खाता है , जबकि \dमैच [0-9]और अन्य अंक वर्ण, उदाहरण के लिए पूर्वी अरबी अंक٠١٢٣٤٥٦٧٨٩


49
के अनुसार: msdn.microsoft.com/en-us/library/20bw873z.aspx If ECMAScript-compliant behavior is specified, \d is equivalent to [0-9].
उपयोगकर्ता 12345678

2
हुह, मैं गलत हूं या लिंक से यह वाक्य विपरीत बता रहा है। "" कोई भी दशमलव अंक से मेल खाता है। यह \ p {Nd} नियमित अभिव्यक्ति पैटर्न के बराबर है, जिसमें मानक दशमलव अंक 0-9 और साथ ही कई अन्य वर्ण सेटों के दशमलव अंक शामिल हैं। "
समेट अलकन

3
@ByteBlast धन्यवाद, कंस्ट्रक्टर का उपयोग: var rex = new Regex(regex, RegexOptions.ECMAScript);प्रदर्शन के संदर्भ में उन सभी को बहुत अधिक अप्रभेद्य बनाता है।
पश्चिमोत्तर

2
ओह वैसे भी, सभी को धन्यवाद। यह प्रश्न मेरे लिए एक बड़ी सीख बन गया।
54समेट अलकैन

3
कृपया अन्य प्रश्नों के उत्तर "बस कॉपी" न करें। यदि प्रश्न डुप्लिकेट है, तो इसे इस तरह ध्वजांकित करें।
BoltClock

20

सीना इवियनियन से शीर्ष उत्तर के अलावा , यहां एक .NET 4.5 संस्करण है (क्योंकि केवल वह संस्करण UTF16 आउटपुट का समर्थन करता है, अपने कोड की पहली तीन पंक्तियों का उपयोग करता है), यूनिकोड कोड बिंदुओं की पूरी श्रृंखला का उपयोग करता है। उच्च यूनिकोड विमानों के लिए उचित समर्थन की कमी के कारण, बहुत से लोग ऊपरी यूनिकोड विमानों के लिए हमेशा जाँच करने और शामिल करने के बारे में नहीं जानते हैं। फिर भी वे कभी-कभी कुछ महत्वपूर्ण पात्रों को शामिल करते हैं।

अपडेट करें

चूंकि \dरेगेक्स (धन्यवाद xanatos ) में गैर-बीएमपी वर्णों का समर्थन नहीं करता है , यहां एक संस्करण है जो यूनिकोड वर्ण डेटाबेस का उपयोग करता है

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

        foreach (var category in new []{
        UnicodeCategory.DecimalDigitNumber,
            UnicodeCategory.LetterNumber,
            UnicodeCategory.OtherNumber})
        {
        sb.AppendLine($"{category}");
            foreach (var ch in charInfo[category])
        {
                sb.Append(ch);
            }
            sb.AppendLine();
        }
    }
    Console.WriteLine(sb.ToString());

    Console.ReadKey();
}

निम्नलिखित उत्पादन उपज:

DecimalDigitNumber 0123456789D02324५६০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯ ९ igit umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber umber

पत्र संख्या

ᛮᛯᛰⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↅↆↇↈ〇〡〢〣〤〥〦〧〨〩〸〹〺ꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ 𐅀𐅁𐅂𐅃𐅄𐅅𐅆𐅇𐅈𐅉𐅊𐅋𐅌𐅍𐅎𐅏𐅐𐅑𐅒𐅓𐅔𐅕𐅖𐅗𐅘𐅙𐅚𐅛𐅜𐅝𐅞𐅟𐅠𐅡𐅢𐅣𐅤𐅥𐅦𐅧𐅨𐅩𐅪𐅫𐅬𐅭𐅮𐅯𐅰𐅱𐅲𐅳𐅴 𐍁𐍊 𐏑𐏒𐏓𐏔𐏕 𒐀𒐁𒐂𒐃𒐄𒐅𒐆𒐇𒐈𒐉𒐊𒐋𒐌𒐍𒐎𒐏𒐐𒐑𒐒𒐓𒐔𒐕𒐖𒐗𒐘𒐙𒐚𒐛𒐜𒐝𒐞𒐟𒐠𒐡𒐢𒐣𒐤𒐥𒐦𒐧𒐨𒐩𒐪𒐫𒐬𒐭𒐮𒐯𒐰𒐱𒐲𒐳𒐴𒐵𒐶𒐷𒐸𒐹𒐺𒐻𒐼𒐽𒐾𒐿𒑀𒑁𒑂𒑃𒑄𒑅𒑆𒑇𒑈𒑉𒑊𒑋𒑌𒑍𒑎𒑏𒑐𒑑𒑒𒑓𒑔𒑕𒑖𒑗𒑘𒑙𒑚𒑛𒑜𒑝𒑞𒑟𒑠𒑡𒑢𒑣𒑤𒑥𒑦𒑧𒑨𒑩𒑪𒑫𒑬𒑭𒑮

OtherNumber²³¹¼½¾৴৵৶.৸৹ ୲୳୴୵୶୷ ௰௱௲ ౸౹౺౻౼౽౾ ൰൱൲൳൴൵ ༪ ༫ ༬ ༭ ༮ ༯ ༰ ༱ ༲ ༳ ፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ ៰ ៱ ៲ ៳ ៴ ៵ ៶ ៷ ៸ ៹ ᧚⁰⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟↉①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓ ⳽ ㆒ ㆓ ㆔ ㆕ ㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㉈㉉㉊㉋㉌㉍㉎㉏㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿꠰꠱꠲꠳꠴꠵𐄇𐄈𐄉𐄊𐄋𐄌𐄍𐄎𐄏𐄐𐄑𐄒𐄓𐄔𐄕𐄖𐄗𐄘𐄙𐄚𐄛𐄜𐄝𐄞𐄟𐄠𐄡𐄢𐄣𐄤𐄥𐄦𐄧𐄨𐄩𐄪𐄫𐄬𐄭𐄮𐄯𐄰𐄱𐄲𐄳𐅵𐅶𐅷𐅸𐆊𐆋𐋡𐋢𐋣𐋤𐋥𐋦𐋧𐋨𐋩𐋪𐋫𐋬𐋭𐋮𐋯𐋰𐋱𐋲𐋳𐋴𐋵𐋶𐋷𐋸𐋹𐋺𐋻 𐌠𐌡𐌢𐌣 𐡘𐡙𐡚𐡛𐡜𐡝𐡞𐡟 𐡹𐡺𐡻𐡼𐡽𐡾𐡿 𐢧𐢨𐢩𐢪𐢫𐢬𐢭𐢮𐢯 𐣻𐣼𐣽𐣾𐣿 𐤖𐤗𐤘𐤙𐤚𐤛 𐦼𐦽𐧀𐧁𐧂𐧃𐧄𐧅𐧆𐧇𐧈𐧉𐧊𐧋𐧌𐧍𐧎𐧏𐧒𐧓𐧔𐧕𐧖𐧗𐧘𐧙𐧚𐧛𐧜𐧝𐧞𐧟𐧠𐧡𐧢𐧣𐧤𐧥𐧦𐧧𐧨𐧩𐧪𐧫𐧬𐧭𐧮𐧯𐧰𐧱𐧲𐧳𐧴𐧵𐧶𐧷𐧸𐧹𐧺𐧻𐧼𐧽𐧾𐧿 𐩀𐩁𐩂𐩃𐩄𐩅𐩆𐩇 𐩽𐩾 𐪝𐪞𐪟 𐫫𐫬𐫭𐫮𐫯 𐭘𐭙𐭚𐭛𐭜𐭝𐭞𐭟 𐭸𐭹𐭺𐭻𐭼𐭽𐭾𐭿 𐮩𐮪𐮫𐮬𐮭𐮮𐮯 𐳺𐳻𐳼𐳽𐳾𐳿 𐹠𐹡𐹢𐹣𐹤𐹥𐹦𐹧𐹨𐹩𐹪𐹫𐹬𐹭𐹮𐹯𐹰𐹱𐹲𐹳𐹴𐹵𐹶𐹷𐹸𐹹𐹺𐹻𐹼𐹽𐹾 𑁒𑁓𑁔𑁕𑁖𑁗𑁘𑁙𑁚𑁛𑁜𑁝𑁞𑁟𑁠𑁡𑁢𑁣𑁤𑁥 𑇡𑇢𑇣𑇤𑇥𑇦𑇧𑇨𑇩𑇪𑇫𑇬𑇭𑇮𑇯𑇰𑇱𑇲𑇳𑇴 𑜺𑜻 𑣪𑣫𑣬𑣭𑣮𑣯𑣰𑣱𑣲 𖭛𖭜𖭝𖭞𖭟𖭠𖭡𝍠𝍡𝍢𝍣𝍤𝍥𝍦𝍧𝍨𝍩𝍪𝍫𝍬𝍭𝍮𝍯𝍰𝍱 𞣇𞣈𞣉𞣊𞣋𞣌𞣍𞣎𞣏🄀🄁🄂🄃🄄🄅🄆🄇🄈🄉🄊🄋🄌


दुःख की बात यह है कि Win32 कंसोल सूक्ष्म पात्रों को प्रदर्शित नहीं करता है
सेबस्टियन

4
अगर मुझे याद है, तो दुख की बात है कि .NET में उदासी Regexगैर-बीएमपी वर्णों का समर्थन नहीं करता है। तो अंत में पात्रों के लिए जाँच> एक rexx के साथ 0xffff बेकार है।
xanatos

-1

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.