2011-10-04 16 views
12

He estado haciendo un poco de trabajo con expresiones regulares durante la última semana y logré hacer un gran progreso, sin embargo, sigo siendo bastante n00b. He una expresión regular escrito en C#:Expresiones regulares en C# ejecutando lentamente

string isMethodRegex = 
    @"\b(public|private|internal|protected)?\s*(static|virtual|abstract)?"+ 
    @"\s*(?<returnType>[a-zA-Z\<\>_1-9]*)\s(?<method>[a-zA-Z\<\>_1-9]+)\s*\"+ 
    @"((?<parameters>(([a-zA-Z\[\]\<\>_1-9]*\s*[a-zA-Z_1-9]*\s*)[,]?\s*)+)\)"; 
IsMethodRegex = new Regex(isMethodRegex); 

Por alguna razón, cuando se llama al IsMethodRegex.IsMatch expresión regular() se cuelga durante más de 30 segundos en la siguiente cadena:

"\t * Returns collection of active STOP transactions (transaction type 30) " 

¿Hay alguien cómo las partes internas de Regex funcionan y por qué esto sería tan lento al hacer coincidir esta cadena y no otras. He jugado con eso y descubrí que si saco el * y el paréntesis, funciona bien. ¿Quizás la expresión regular está mal escrita?

Cualquier ayuda sería tan apreciada.

+2

¿Ha intentado compilar la expresión regular? Una de las sobrecargas del constructor proporciona esta capacidad. –

+0

@Steve: Acabo de probarme y, después de compilarlo, todavía lleva mucho tiempo. Puedo reproducir el largo tiempo en mi propia máquina en LinqPad. – mellamokb

+2

Sé que esto no viene al caso, pero su expresión regular se ve muy frágil para mí. De alguna manera, creo que el rendimiento es el menor de tus problemas. – ChaosPandion

Respuesta

3

EDIT: Creo que el problema de rendimiento viene en la forma en que <parameters> grupo coincidente está hecho. He reorganizado para que coincida con un primer parámetro, luego cualquier número de parámetros sucesivos u opcionalmente ninguno. También he cambiado el \s* entre el tipo de parámetro y el nombre a \s+ (creo que esto fue responsable de MUCHO retroceso porque no permite espacios, de modo que object podría coincidir como obj y ect con \s* sin espacios) y parece que se ejecuta mucho más rápido:

string isMethodRegex = 
    @"\b(public|private|internal|protected)?\s*(static|virtual|abstract)?"+ 
    @"\s*(?<returnType>[a-zA-Z\<\>_1-9]*)\s*(?<method>[a-zA-Z\<\>_1-9]+)\s*\"+ 
    @"((?<parameters>((\s*[a-zA-Z\[\]\<\>_1-9]*\s+[a-zA-Z_1-9]*\s*)"+ 
    @"(\s*,\s*[a-zA-Z\[\]\<\>_1-9]*\s+[a-zA-Z_1-9]*\s*)*\s*))?\)"; 

EDITAR: Como debidamente señalado por @ Dan, el siguiente es simplemente porque la expresión regular puede salir temprano.

Esta es de hecho una situación muy extraña, pero si quito los dos coincidente opcional al principio (para público/privado/interno/protegido y estática/virtual/abstracto), entonces comienza a funcionar de forma casi instantánea de nuevo:

string isMethodRegex = 
    @"\b(public|private|internal|protected)\s*(static|virtual|abstract)"+ 
    @"(?<returnType>[a-zA-Z\<\>_1-9]*)\s(?<method>[a-zA-Z\<\>_1-9]+)\s*\"+ 
    @"((?<parameters>(([a-zA-Z\[\]\<\>_1-9]*\s*[a-zA-Z_1-9]*\s*)[,]?\s*)+)\)"; 
var IsMethodRegex = new Regex(isMethodRegex); 

string s = "\t * Returns collection of active STOP transactions (transaction type 30) "; 

Console.WriteLine(IsMethodRegex.IsMatch(s)); 

Técnicamente podría dividirse en cuatro Regex por separado para cada posibilidad de hacer frente a esta situación particular. Sin embargo, a medida que intente lidiar con escenarios cada vez más complicados, probablemente se encontrará con este problema de rendimiento una y otra vez, por lo que probablemente este no sea el enfoque ideal.

+0

El resultado de esto es un 'falso', ¿correcto? Puede excluir el partido inmediatamente porque no comienza con 'p' o 'i', por lo que es una búsqueda trivial. –

+0

@Dan: De hecho, tienes razón. Sospecho que tiene algo que ver con la forma en que se realiza la parte ''. – mellamokb

3

me cambió algunas 0-o más-(*) emparejamientos con 1-o-más (+), en el que que que tiene sentido para su expresión regular (es más adecuado para Java y C# que a VB.NET):

string isMethodRegex = 
    @"\b(public|private|internal|protected)?\s*(static|virtual|abstract)?" + 
    @"\s*(?<returnType>[a-zA-Z\<\>_1-9]+)\s+(?<method>[a-zA-Z\<\>_1-9]+)\s+\" + 
    @"((?<parameters>(([a-zA-Z\[\]\<\>_1-9]+\s+[a-zA-Z_1-9]+\s*)[,]?\s*)+)\)"; 

Es rápido ahora.

Compruebe si todavía le devuelve el resultado que espera.

Para obtener más información sobre las expresiones regulares incorrectas, consulte here.

1

¿Ha intentado compilar su Regex?

string pattern = @"\b[at]\w+"; 
RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Compiled; 
string text = "The threaded application ate up the thread pool as it executed."; 
MatchCollection matches; 

Regex optionRegex = new Regex(pattern, options); 
Console.WriteLine("Parsing '{0}' with options {1}:", text, options.ToString()); 
// Get matches of pattern in text 
matches = optionRegex.Matches(text); 
// Iterate matches 
for (int ctr = 1; ctr <= matches.Count; ctr++) 
    Console.WriteLine("{0}. {1}", ctr, matches[ctr-1].Value); 

Luego, la Expresión regular solo es lenta en la primera ejecución.

+0

Ya lo intentamos, no hizo ninguna diferencia. De hecho, hubo una respuesta que decía lo mismo hace un tiempo que el autor eliminó. – mellamokb

Cuestiones relacionadas