当前位置: 首页 > 知识库问答 >
问题:

为什么\d比[0-9]慢?

葛鸿轩
2023-03-14

我昨天对一个答案发表了评论,其中有人在正则表达式中使用了[0123456789],而不是[0-9]\d。我说使用范围或数字说明符可能比使用字符集更快。

我决定今天测试一下,并惊讶地发现(至少在C#regex引擎中)\d似乎比其他两个似乎没有太大区别的任何一个都慢。这是我的测试输出超过10000个随机字符串,其中包含1000个随机字符,其中5077个实际上包含一个数字:

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

这对我来说是一个惊喜,有两个原因,如果有人能解释一下,我会很感兴趣:

  1. 我本以为这个范围会比set更有效地实现
  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 1 char 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;
        }
    }
}

共有3个答案

慕容越泽
2023-03-14

从 正则表达式中的“\d”是否表示数字?:

< code>[0-9]不等同于< code>\d。< code>[0-9]仅匹配< code>0123456789字符,而< code>\d匹配< code>[0-9]和其他数字字符,例如东方阿拉伯数字٠١٢٣٤٥٦٧٨٩

锺离辰沛
2023-03-14

感谢ByteBlast在文档中注意到了这一点。只需更改正则表达式构造函数:

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
南门欣怡
2023-03-14

< code>\d检查所有Unicode数字,而< code>[0-9]仅限于这10个字符。例如,波斯语数字۱۲۳۴۵۶۷۸۹是与< code>\d匹配的Unicode数字的一个例子,但不与< code>[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());

产生:

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

 类似资料:
  • 今天我决定测试一下,结果我惊讶地发现(至少在C#正则表达式引擎中)似乎比其他两个没有太大区别的代码效率要低。下面是我测试输出的10000个由1000个随机字符组成的字符串,其中5077个实际包含一个数字: 这对我来说是一个惊喜,有两个原因,如果有人能给我一些启示,我会很感兴趣: 我本以为范围的实现会比集合的实现效率高得多。 我不能理解为什么比差。除了的简写之外,还有其他内容吗? 下面是测试代码:

  • 问题内容: 我试图实施Miller- Rabin素数测试 ,并且对为什么中型数字(〜7位数字)花费如此长时间(> 20秒)感到困惑。我最终发现以下代码行是问题的根源: (其中,和都是相似的,但不相等的中号,是幂运算符,并且是模运算符) 然后,我尝试将其替换为以下内容: 相比之下,它几乎是瞬时的。 对于上下文,这是原始功能: 定时计算示例: 输出(与PyPy 1.9.0一起运行): 输出(在Pyth

  • 问题内容: 为什么比Java 慢?换句话说,为什么优于? 当我查看中的实现时,速度似乎应该是相同的: ArrayList.size() ArrayList.isEmpty() 如果我们只编写一个简单的程序来获取两种方法所花费的时间,那么在所有情况下这种情况都将花费更多,为什么会这样呢? 这是我的TestCode; 在所有情况下都在这里。为什么? 问题答案: 您的测试代码有缺陷。 只需颠倒顺序,即先

  • 问题内容: 我正在学习Go,并且一直沉迷于Go旅游(exercise- stringer.go:https : //tour.golang.org/methods/7)。 这是一些代码: 所以我想出了is 的内部表示,所以散布算子起作用了。但我得到: 有没有搞错?字符串切片也不起作用,这是怎么回事? 编辑 :对不起,我的问题中有一个错误- 错误是关于type的,不是。我在玩代码,并且粘贴了错误的输

  • 问题内容: 我在进行一些MySQL测试查询,并意识到将字符串列与(作为数字)进行比较可以得出! 但是,将其与其他任何数字(正数或负数,整数或十进制数)进行比较,将得到预期的结果(当然,除非字符串是数字以字符串的形式表示) 当然,按预期将字符串与as字符串进行比较会得出false。 但是,为什么它如此呢? 这是为什么? 问题答案: MySQL自动将字符串转换为数字: 不以数字开头的字符串的值为0:

  • 问题内容: 我必须编写一个例程,如果变量的类型为,则将变量的值加1,否则将变量的值分配为0,其中变量的初始值为或。 第一个实现是因为我认为没有数字会使算术表达式为假,但是由于计算为真,所以这是错误的。然后,我得知行为类似于0,并且以下表达式均被评估为true。 当然不是0。被评估为false。这使看似重言式的表达成为错误。 为什么实际上不是0,却像0? 问题答案: 您真正的问题似乎是: 为什么: