Ho fatto un commento ieri una risposta in cui qualcuno aveva usato [0123456789]
in un'espressione regolare piuttosto che [0-9]
o \d
. Ho detto che probabilmente era più efficiente usare un identificatore di intervallo o cifra di un set di caratteri.
Ho deciso di provarlo oggi e ho scoperto con mia sorpresa che (almeno nel motore regex C #) \d
sembra essere meno efficiente di uno degli altri due che non sembrano differire molto. Ecco il mio output di test su oltre 10000 stringhe casuali di 1000 caratteri casuali con 5077 che in realtà contengono una cifra:
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
È una sorpresa per me per due motivi:
- Avrei pensato che la gamma sarebbe stata implementata in modo molto più efficiente rispetto al set.
- Non riesco a capire perché
\d
sia peggio di[0-9]
. C'è di più\d
che una semplice scorciatoia per[0-9]
?
Ecco il codice di prova:
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 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
non significa la stessa cosa in lingue diverse. In Java, ad esempio \d
, corrisponde effettivamente solo allo 0-9
\d
occupa di locali. Ad esempio l'ebraico usa le lettere per le cifre.