Ich habe gestern einen Kommentar zu einer Antwort gemacht, in der jemand [0123456789]
in einem Regex verwendet hat, anstatt [0-9]
oder \d
. Ich habe gesagt, dass es wahrscheinlich effizienter ist, einen Bereich oder einen Ziffernspezifizierer zu verwenden als eine Zeichenmenge.
Heute habe ich beschlossen, das zu testen und zu meiner Überraschung herausgefunden, dass (zumindest im c# Regex-Engine) \d
anscheinend weniger effizient ist als die anderen beiden, die sich nicht viel zu unterscheiden scheinen. Hier ist meine Testausgabe über 10000 zufällige Zeichenfolgen mit jeweils 1000 zufälligen Zeichen, von denen 5077 tatsächlich eine Ziffer enthalten:
Regex \d dauerte 00:00:00.2141226 Ergebnis: 5077/10000
Regex [0-9] dauerte 00:00:00.1357972 Ergebnis: 5077/10000 63.42 % des ersten
Regex [0123456789] dauerte 00:00:00.1388997 Ergebnis: 5077/10000 64.87 % des ersten
Das überrascht mich aus zwei Gründen, über die ich gerne mehr erfahren würde:
- Ich hätte gedacht, dass der Bereich viel effizienter implementiert wäre als die Menge.
- Ich verstehe nicht, warum
\d
schlechter ist als[0-9]
. Gibt es mehr zu\d
als nur eine Abkürzung für[0-9]
?
Hier ist der Testcode:
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();
//10K zufällige Zeichenfolgen
for (var i = 0; i < 10000; i++)
{
//zufällige Zeichenfolge generieren
var sb = new StringBuilder();
for (var c = 0; c < 1000; c++)
{
//zufällig a-z hinzufügen
sb.Append((char)('a' + rand.Next(26)));
}
//in ungefähr 50 % von ihnen, eine Ziffer einfügen
if (rand.Next(2) == 0)
{
//Ersetze 1 Zeichen durch eine Ziffer 0-9
sb[rand.Next(sb.Length)] = (char)('0' + rand.Next(10));
}
strings.Add(sb.ToString());
}
var basisZeit = testPerfomance(strings, @"\d");
Console.WriteLine();
var testZeit = testPerfomance(strings, "[0-9]");
Console.WriteLine(" {0:P2} des ersten", testZeit.TotalMilliseconds / basisZeit.TotalMilliseconds);
testZeit = testPerfomance(strings, "[0123456789]");
Console.WriteLine(" {0:P2} des ersten", testZeit.TotalMilliseconds / basisZeit.TotalMilliseconds);
}
private static TimeSpan testPerfomance(List strings, string regex)
{
var sw = new Stopwatch();
int erfolge = 0;
var rex = new Regex(regex);
sw.Start();
foreach (var str in strings)
{
if (rex.Match(str).Success)
{
erfolge++;
}
}
sw.Stop();
Console.Write("Regex {0,-12} dauerte {1} Ergebnis: {2}/{3}", regex, sw.Elapsed, erfolge, strings.Count);
return sw.Elapsed;
}
}
}