\ d效率低于

我昨天发表了一个评论,有人用[0123456789]作为正则expression式而不是[0-9]\d 。 我说,使用范围或数字说明符可能比字符集更有效。

我决定今天testing一下,发现令我吃惊的是(至less在C#正则expression式引擎中) \d似乎比其他两个似乎没有太大的差别。 这是我的testing输出超过10000随机string1000个随机字符与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]更糟糕。 除了简单的[0-9]之外还有更多的东西吗?

这里是testing代码:

 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 az 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检查所有的Unicode数字,而[0-9]仅限于这10个字符。 例如, 波斯数字۱۲۳۴۵۶۷۸۹是与\d匹配的Unicode数字的一个例子,但不是[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߀߁߂߃߄߅߆߇߈߉012345678901২345678901234567890123456789୦୧୨୩୪୫୬୭୮୯0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙0123456789

感谢ByteBlast在文档中注意到这一点。 只是改变正则expression式的构造函数:

 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 

从正则expression式中的“\ D”是指数字? :

[0-9]不等于\d[0-9]只匹配0123456789字符,而\d匹配[0-9]和其他数字字符,例如Eastern阿拉伯数字٠١٢٣٤٥٦٧٨٩

除了来自Sina Iravianian的 顶级答案 之外 ,这里是一个.NET 4.5版本(因为只有该版本支持UTF16输出,比较前三行),使用全部的Unicode代码点。 由于缺乏对更高级的Unicode平面的适当支持,许多人不知道总是检查并包括上面的Unicode平面。 尽pipe如此,他们有时也包含一些重要的人物

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

产生以下输出:

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

\ d会检查所有的Unicode,而[0-9]仅限于这10个字符。 如果只有10位数字,你应该使用。 其他我推荐使用\ d,因为写得less。

\d将会效率较低,因为必须进行转换才能进行比较。

例如,如果我想让RegexfindIP地址,我宁可用[0123456789]甚至[0-9]来表示任何数字。

一般来说在我的正则expression式中使用,function比速度更重要。