昨日、誰かがまたは[0123456789]
ではなく 正規表現を使用していた回答にコメントしました。文字セットよりも範囲指定子または数字指定子を使用する方がおそらく効率的だと述べました。[0-9]
\d
今日それをテストしてみることにしましたが、驚いたことに、(少なくとも C# 正規表現エンジンでは)\d
あまり違いがないように見える他の 2 つよりも効率が悪いようです。以下は、1000 個のランダムな文字からなる 10000 個のランダムな文字列 (実際に数字が含まれているのは 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
これは私にとって 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;
}
}
}
ベストアンサー1
\d
はすべてのUnicode数字をチェックしますが、[0-9]
はこれらの10文字に制限されます。たとえば、ペルシャ語数字は と一致しますが とは一致しない۱۲۳۴۵۶۷۸۹
Unicode 数字の例です。\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());
生成されるもの:
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹րցւփքօֆևֈ։०१२३४५६७८९০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬ ૭૮૯୦୧୨୩୪୫୬୭୮୯௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮൯๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤ ༥༦༧༨༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱ ᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙0123456789