Hice un comentario ayer sobre una respuesta donde alguien había usado [0123456789]
una expresión regular en lugar de [0-9]
o \d
. Dije que probablemente era más eficiente usar un rango o un especificador de dígitos que un conjunto de caracteres.
Decidí probar eso hoy y descubrí para mi sorpresa que (al menos en el motor C # regex) \d
parece ser menos eficiente que cualquiera de los otros dos, que no parecen diferir mucho. Aquí está mi salida de prueba sobre 10000 cadenas aleatorias de 1000 caracteres aleatorios con 5077 que realmente contienen un dígito:
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
Es una sorpresa para mí por dos razones:
- Pensé que el rango se implementaría de manera mucho más eficiente que el conjunto.
- No puedo entender por qué
\d
es peor que[0-9]
. ¿Hay algo más\d
que una simple taquigrafía[0-9]
?
Aquí está el código de prueba:
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;
}
}
}
c#
regex
performance
Weston
fuente
fuente
\d
trata de locales. Por ejemplo, el hebreo usa letras para los dígitos.\d
no significa lo mismo en diferentes idiomas. En Java, por ejemplo\d
, solo coincide 0-9 soloRespuestas:
\d
comprueba todos los dígitos Unicode, mientras que[0-9]
está limitado a estos 10 caracteres. Por ejemplo, los dígitos persas۱۲۳۴۵۶۷۸۹
, son un ejemplo de dígitos Unicode que coinciden con\d
, pero no[0-9]
.Puede generar una lista de todos esos caracteres utilizando el siguiente código:
Lo que genera:
fuente
Gracias a ByteBlast por notar esto en los documentos. Solo cambiando el constructor regex:
Da nuevos horarios:
fuente
RegexOptions.ECMAScript
?ECMAScript
(\u1234
). Es "solo" las clases de caracteres abreviados que cambian el significado (como\d
) y las propiedades de Unicode / script shorthands que desaparecen (como\p{N}
).¿ De "\ d" en regex significa un dígito? :
fuente
If ECMAScript-compliant behavior is specified, \d is equivalent to [0-9].
var rex = new Regex(regex, RegexOptions.ECMAScript);
hace prácticamente indistinguibles en términos de rendimiento.Una adición a la respuesta principal de Sina Iravianian , aquí hay una versión .NET 4.5 (ya que solo esa versión admite la salida UTF16, cf las primeras tres líneas) de su código, usando la gama completa de puntos de código Unicode. Debido a la falta de soporte adecuado para los planos Unicode superiores, muchas personas no son conscientes de siempre verificar e incluir los planos Unicode superiores. Sin embargo, a veces contienen algunos personajes importantes.
Actualizar
Como
\d
no admite caracteres que no sean BMP en expresiones regulares (gracias xanatos ), aquí hay una versión que utiliza la base de datos de caracteres UnicodeProduciendo el siguiente resultado:
fuente
Regex
no admite caracteres que no sean BMP. Entonces, al final, la comprobación de caracteres> 0xffff con una expresión regular es inútil.\ d verifica todos los Unicode, mientras que [0-9] está limitado a estos 10 caracteres. Si solo tiene 10 dígitos, debe usar. Otros recomiendo usar \ d, porque escribir menos.
fuente