\ 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
有两个原因令我感到惊讶:
- 我会认为范围将比集合更有效地执行。
- 我不明白为什么
\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比速度更重要。