Vraag Reguliere expressies in C # lopen langzaam


Ik heb de afgelopen week een beetje gewerkt met regex en heb veel vooruitgang geboekt, maar ik ben nog steeds redelijk n00b. Ik heb een regex geschreven in C #:

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);

Om een ​​bepaalde reden hangt het bij het aanroepen van de reguliere expressie IsMethodRegex.IsMatch () 30+ seconden op aan de volgende string:

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

Heeft iemand hoe de interne functies van Regex werken en waarom dit zo traag zou zijn met het matchen van deze string en niet met andere. Ik heb er een spel mee gespeeld en ontdekte dat als ik de * en de haakjes verwijder, het goed werkt. Misschien is de reguliere expressie slecht geschreven?

Alle hulp zou zo enorm gewaardeerd worden.


12
2017-10-04 00:02


oorsprong


antwoorden:


BEWERK: Ik denk dat het probleem met de prestaties in de weg zit <parameters> passende groep is klaar. Ik ben opnieuw ingedeeld om een ​​eerste parameter overeen te laten komen, vervolgens een willekeurig aantal opeenvolgende parameters, of optioneel helemaal geen. Ook heb ik de \s* tussen parametertype en naam in \s+ (Ik denk dat dit verantwoordelijk was voor VEEL backtracking omdat het geen spaties toestaat, dus dat object kon matchen als obj en ect met \s* matching geen spaties) en het lijkt veel sneller te lopen:

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*))?\)";

BEWERK: Zoals naar behoren is aangegeven door @Dan, is het volgende eenvoudigweg omdat de Regex vroegtijdig kan afsluiten.

Dit is inderdaad een hele bizarre situatie, maar als ik de twee optionele overeenkomsten aan het begin verwijder (voor openbaar / privé / intern / beschermd en statisch / virtueel / abstract), dan begint het bijna onmiddellijk weer te lopen:

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));

Technisch gezien zou je in vier afzonderlijke Regex's kunnen splitsen voor elke mogelijkheid om met deze specifieke situatie om te gaan. Als u echter steeds meer gecompliceerde scenario's probeert op te lossen, zult u deze prestatieproblematiek waarschijnlijk keer op keer tegenkomen, dus dit is waarschijnlijk niet de ideale aanpak.


3
2017-10-04 00:34



Ik heb enkele 0-of-meer (*) overeenkomsten gewijzigd met 1-of-meer (+), waar ik denken het is logisch voor je regex (het is meer geschikt voor Java en C # dan voor 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*)+)\)";

Het is snel nu.

Controleer of het resultaat dat u verwacht nog steeds wordt weergegeven.

Voor een achtergrond over slechte regexes, kijk hier.


3
2017-10-04 00:48



Heb je geprobeerd je Regex te compileren?

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);

Dan is de reguliere expressie bij de eerste uitvoering slechts traag.


1
2017-10-04 00:57