RegEx IsMatch ist langsam

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    RegEx IsMatch ist langsam

    Hallo Community,

    Ich bin habe sogut wie nochnie mit RegEx gearbeitet, habe aber mit ein bisschen mich einlesen und rum experimentieren ein gutes pattern für meine Zwecke zusammen gebastelt.

    Dies ist mein pattern: ^[[|\(](.*){0,20}(]|\))(\s|)[[|\(][a-zA-Z]{1}(]|\))(\s|)(?<=(\s|))(.*)(?=(\s|)[[|\(])(\s|)[[|\(][a-zA-Z]{1}(]|\))(\s|)(.*)

    Das Pattern brauche ich um zu überprüfen ob eine Nachricht ein bestimmtes Format einhält.
    Das Format das die Nachricht haben soll:
    [PLATFORM] [H] item... [W] item...
    oder
    (PLATFORM) (H) item... (W) item...

    Methode zum überpüfen der Nachricht:

    C#-Quellcode

    1. bool isMatch = Regex.IsMatch(arg.Content, @"^[[|\(](.*){0,20}(]|\))(\s|)[[|\(][a-zA-Z]{1}(]|\))(\s|)(?<=(\s|))(.*)(?=(\s|)[[|\(])(\s|)[[|\(][a-zA-Z]{1}(]|\))(\s|)(.*)");


    Jetzt meine Frage: Wie kann ich das Pattern verbessern so das es Nachrichten schneller überprüft werden können?
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    puh!
    zunächstmal fällt mir dieses Detail auf:(.*){0,20}
    kann man da das {0,20} nicht weglassen?

    Auch hier: [a-zA-Z]{1} scheint mir die Zahlen-Angabe üflüssig: eins ist halt eins - braucht man nicht nochmal zu definieren.

    Ah - ich arbeite immer mit Regex-Objekten, die ich einmal erstelle und wiederverwende - vermutlich hat das auch eine bessere Performance.

    C#-Quellcode

    1. private Regex _rgxFormat = new Regex(@"^[[|\(](.*)(]|\))(\s|)[[|\(][a-zA-Z](]|\))(\s|)(?<=(\s|))(.*)(?=(\s|)[[|\(])(\s|)[[|\(][a-zA-Z](]|\))(\s|)(.*)");
    2. //...
    3. bool isMatch = _rgxFormat.IsMatch(arg.Content);

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Jo, {0,20} und {1} kann ruig weg. Ist wirklich etwas überflüssig.

    Ich werd's mal mit Regex-Objekten versuchen. Danke!
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Implementiere doch einfach selbst einen endlichen Automaten der alle Sprachen akzeptiert die mit [Pla... oder (Pla.... beginnen, beliebig viele Zeichen folgen, dann ein (H) folgt, beliebig viele Zeichen darauffolgend (W)/[W] akzeptiert und mit beliebig vielen Zeichen endet.

    _
    Und Gott alleine weiß alles am allerbesten und besser.

    φConst schrieb:

    Implementiere doch einfach selbst einen endlichen Automaten der alle Sprachen akzeptiert
    Jo - mach du das!



    Ich jdfs hab mein Regextester - OpenSource angeworfen und konnte einiges aus dem gegebenen Pattern rausschmeissen / korrigieren, was mir komisch vorkam.
    Kommt bislang dieses raus: ^[\[\(](.*)[\]\)]\s*[\[\(]([a-zA-Z])[\]\)](.*)[\[\(]([a-zA-Z])[\]\)](.*)
    Input habich folgende eingegeben:

    Quellcode

    1. [PLATFORM] [H]item H... [W]itemW...
    2. [PLitfrm] [H] itemH... [W] itemW...
    3. (PLATFORM) (B) itemB (W) itemW
    4. [PLATFORM] (B) itemB [X] itemX

    In mein Regextester kann man die Pattern mehrzeilig aufbauen, und so einzelne Bereiche/Gruppen besser verstehen, etwa so:

    Quellcode

    1. ^[\[\(]
    2. (.*)
    3. [\]\)]
    4. \s*
    5. [\[\(]
    6. ([a-zA-Z])
    7. [\]\)]
    8. (.*)
    9. [\[\(]
    10. ([a-zA-Z])
    11. [\]\)]
    12. (.*)
    Wie man vielleicht sieht, habe ich 5 aufzeichnende Gruppen eingebaut, wo man die Inhalte also auslesen kann - sieht in mein RTester so aus:

    Man könnte noch einiges mehr machen.
    • Insbesondere fraglich finde ich, dass auch input#4 matcht, der eine Mixtur von [], () aufweist - mein gefühl sagt mir, das sollte nicht erlaubt sein.
    • Weiters kommen bei meim Pattern auch führende + folgende Spaces in die Gruppen hinein.
      Bislang wurde da genau 1 Space entfernt, und wenns mehrere waren, kamen eben doch welche rein.
      Will man Spaces aus den Gruppen weg-trimmen muss man anders vorgehen.

    ErfinderDesRades schrieb:

    Jo - mach du das!

    Aber dann hätte er doch nichts zu tun (;?
    Einen endlichen Automaten zu realisieren ist extrem simpel.
    Wird halt bei seinem Beispiel extrem viele Zustände haben, ist aber vermutlich dennoch effizienter als das was er da gerade versucht.
    Alternativ muss er ja nicht unbedingt auf Buchstaben arbeiten - er kann ja einfach das Alphabet über ganze Wörter definieren - das reduziert die Anzahl der Zustände drastisch.
    Und Gott alleine weiß alles am allerbesten und besser.
    Ich würde den umschreiben in ^[\[\(]([^\]\)]+)[\]\)]\s*(?:[\[\(]([^\]\)]+)[\]\)]\s*(.+))[\[\(]([^\]\)]+)[\]\)]\s*(.+)

    mit den beispielen von @ErfinderDesRades

    ErfinderDesRades schrieb:

    Ah - ich arbeite immer mit Regex-Objekten, die ich einmal erstelle und wiederverwende - vermutlich hat das auch eine bessere Performance.

    Nicht vermutlich, hat auch, denn er muss nicht jedes mal neu den Patter parsen.

    φConst schrieb:

    Einen endlichen Automaten zu realisieren ist extrem simpel.
    Sorry, aber dassis Quatsch, Angeberei, Aprilscherz und/oder wasweissich.

    Aber wenns so simpel ist, beweise es. Kannst deine Lösung ja hier anhängen - bin gespannt.
    Kann dir ja nicht soviel Aufwand bereiten - simpel wie das ist.
    Und kann ich vlt. was lernen.
    Endliche Automaten hat man im ersten Semester im Modul theoretische Informatik. Da implementiert man dann auch einen endlichen Automaten der eine bestimmte Sprache akzeptiert. Das sind nur Zustandswechsel. Was soll bitteschön daran schwer sein? Zustand q0, dort liest er ein Wort, wechselt entweder zu q1, oder q2, andere Wörter führen jeweils wieder zu sich selbst, bis der ein [...]/(...) findet und wieder Zustand wechselt, bis er im akzeptierenden Zustand ist (zB weil es ein Epsilon las, denn die Sprache endet ja mit beliebigen Zeichen).
    Das ist eine reguläre Sprache - die simpelste aller Sprachen. (Kontextfrei wäre halt bissel schwerer, bräuchte dann einen Kellerautomaten).

    Im Moment habe ich zu tun, wenn ich Zeit habe implementiere ich es vielleicht'.
    Kann sein, das ich die reguläre Sprache zu dieser Aufgabe unterschätze, aber es beginnt doch mit [irgendwas], oder nicht?
    _
    Und Gott alleine weiß alles am allerbesten und besser.
    Also würdest du hingehen und

    Quellcode

    1. Ist [ oder (, dann
    2. Wiederhole solange Ist gefolgt von 'A' bis 'Z' oder 'a' bis 'z' und nicht ')' oder nicht ']' dann
    3. Sammeln
    4. End Wiederhole
    5. Spring 1 weiter
    6. Wiederhole solange ist ' '
    7. Spring 1 weiter
    8. End Wiederhole
    9. ...
    10. ENDE


    Ich glaub das macht Regex besser :D
    Nein, das ist ziemlich unschön was du da machst. Endlich Automaten arbeiten mit Zuständen. Pro eingelesenes Wort wird entschieden, welcher Zustand folgt. RegEx (also die Klasse, ansonsten ist es einfach die Sprache) ist NICHTS anderes. Es parst einfach ein gewisses Pattern und erzeugt dazu einen passenden endlichen Automaten der diese Sprache akzeptiert. Es gibt zu jedem regulären Ausdruck einen passenden Automaten (Beweis erfolgt über Kombination von Blackbox-Automaten).
    Aber im ernst, statt zu reden, mache ich es vielleicht einfach selbst. Kann verstehen wenn ich gerade ein wenig provokativ wirke.
    Und Gott alleine weiß alles am allerbesten und besser.
    Ähmmm.. Ich denke ich bleibe lieber bei Regex :P

    @ErfinderDesRades Ich habe bis jetzt immer zum testen meines Patterns diese Webseite genommen: regexr.com/
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    .... es ist RegEx (regular Expression => reguläre Ausdrücke => endliche Automaten) was ich hier schreibe, ich habe dir als Tipp nur mitgeben wollen, selbst einen endlichen Automaten zu erstellen, statt den dir generieren zu lassen. So kannst du schneller vorgehen und zudem an beliebig vielen Stellen optimieren. Das war kein OffTopic was ich schrieb.
    Und Gott alleine weiß alles am allerbesten und besser.
    Hier mal der endliche Automat das Sprachen der Form (...) (a) ... (b) ... akzeptiert:

    Spoiler anzeigen

    C#-Quellcode

    1. public class SpecifiedFiniteStateMachine
    2. {
    3. public enum State
    4. {
    5. qInit,
    6. qBracketOpen0,
    7. qBracketClose0,
    8. qBracketOpen1,
    9. qBracketClose1,
    10. qBracketOpen2,
    11. qBracketClose2,
    12. qSpaceB0,
    13. qSpaceB1,
    14. qSpaceB2,
    15. qSpaceB3,
    16. qFinal
    17. }
    18. public State AcceptingState { get; set; }
    19. public bool Accept(string input)
    20. {
    21. State currentState = State.qInit;
    22. int index = 0;
    23. while(index < input.Length && currentState != AcceptingState)
    24. {
    25. var t = input[index];
    26. switch (currentState)
    27. {
    28. case State.qInit:
    29. if (input[index] == '(')
    30. {
    31. currentState = State.qBracketOpen0;
    32. index++;
    33. }
    34. else return false;
    35. break;
    36. case State.qBracketOpen0:
    37. if (input[index++] == ')')
    38. currentState = State.qBracketClose0;
    39. break;
    40. case State.qBracketClose0:
    41. if (input[index++] == ' ')
    42. currentState = State.qSpaceB0;
    43. else return false;
    44. break;
    45. case State.qSpaceB0:
    46. if (input[index++] != ' ')
    47. {
    48. currentState = State.qBracketOpen1;
    49. index++;
    50. }
    51. else return false;
    52. break;
    53. case State.qBracketOpen1:
    54. if (input[index++] == ')')
    55. {
    56. currentState = State.qBracketClose1;
    57. }
    58. else return false;
    59. break;
    60. case State.qBracketClose1:
    61. if (input[index++] == ' ')
    62. currentState = State.qSpaceB1;
    63. else return false;
    64. break;
    65. case State.qSpaceB1:
    66. if (input[index++] == ' ')
    67. currentState = State.qSpaceB2;
    68. break;
    69. case State.qSpaceB2:
    70. if (input[index++] == '(')
    71. {
    72. currentState = State.qBracketOpen2;
    73. index++;
    74. }
    75. break;
    76. case State.qBracketOpen2:
    77. if (input[index++] == ')')
    78. currentState = State.qBracketClose2;
    79. else return false;
    80. break;
    81. case State.qBracketClose2:
    82. if (input[index++] == ' ')
    83. currentState = State.qSpaceB3;
    84. else return false;
    85. break;
    86. case State.qSpaceB3:
    87. if (input[index++] != ' ')
    88. currentState = State.qFinal;
    89. break;
    90. }
    91. }
    92. return currentState == AcceptingState;
    93. }
    94. }



    Aufruf:

    C#-Quellcode

    1. static void Main(string[] args)
    2. {
    3. SpecifiedFiniteStateMachine specifiedFiniteStateMachine
    4. = new SpecifiedFiniteStateMachine();
    5. specifiedFiniteStateMachine.AcceptingState = SpecifiedFiniteStateMachine.State.qFinal;
    6. string s = "(PLATFORM) (B) itemB (W) itemW ";
    7. Console.WriteLine(specifiedFiniteStateMachine.Accept(s)); // true
    8. s = "(PLAfkrM) (B) itemB (W) itemW";
    9. Console.WriteLine(specifiedFiniteStateMachine.Accept(s)); // true
    10. s = "(OJRGIPRJIG00000) (B) itemiorghrgregregore (W) itemW";
    11. Console.WriteLine(specifiedFiniteStateMachine.Accept(s)); // true
    12. s = "(PLAfkrM)(B) itemB (W) itemW";
    13. Console.WriteLine(specifiedFiniteStateMachine.Accept(s)); // false
    14. s = "(PLAfkrM) (B)itemB (W) itemW";
    15. Console.WriteLine(specifiedFiniteStateMachine.Accept(s)); // false
    16. Console.Read();
    17. }


    Kann sein, dass es noch hier und da Fehler gibt, hab es' auf die Schnelle implementiert.
    Dasselbe analog für [...] [x] ... [y] ...

    Ich habe "item..." als beliebig viele Zeichen interpretiert. Falls dem nicht so ist, sieht der Automat ein wenig anders aus. Aber es soll ja ein Anreiz sein, dass du das selbst implementierst.

    @ErfinderDesRades Es ist einfach - was denkst du findet im Hintergrund statt? Es wird zu einem regulären Ausdruck einfach ein endlicher Automat erzeugt. Guck dir das mal an:

    _
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „φConst“ ()

    Also mit dem Pattern habe ich nun keine Probleme mehr: ^[[|\(](.+)(]|\))(\s|)[[|\(][a-zA-Z](]|\))(\s|)(?<=(\s|))(.*)(?=(\s|)[[|\(])(\s|)[[|\(][a-zA-Z](]|\))(\s|)(.+)
    Regex.IsMatch ist nun wieder super schnell^^

    Das Thema hätte sich für mich erledigt.
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Naja, wenn du meinst. Dennoch empfehle ich dir endliche Automaten zu verstehen, statt einfach irgendwelche Pattern (z.B. try&error-mäßig) zu tippen.
    Das ist kein Hexenwerk, endliche Automaten sind simpel, auch wenn es nicht jeder so sieht.
    Und Gott alleine weiß alles am allerbesten und besser.
    Naja, wenn ich mich erstmal mehr damit beschaftige wird es später auch kein try&error-mäßiges Tippen mehr ^^
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    ClonkAndre schrieb:

    Also mit dem Pattern habe ich nun keine Probleme mehr: ^[[|\(](.+)(]|\))(\s|)[[|\(][a-zA-Z](]|\))(\s|)(?<=(\s|))(.*)(?=(\s|)[[|\(])(\s|)[[|\(][a-zA-Z](]|\))(\s|)(.+)
    Das ist aber doch voll der Rückschritt gegenüber was ich ausbaldovert habe.
    Funzt glaub auch nicht richtig - probiermal mit

    Quellcode

    1. [PLitfrm] [H] itemH... [W] itemW...
    2. |PLATFORM] (B) itemB [X] itemX
    #1 matcht nicht, obwohl sie glaub sollte
    #2 matcht, obwohl nicht sollte

    Und dann sind wieder die unsinnigen Nichtaufzeichnenden Gruppen drin: (?...)
    Und unangemessene bzw. disfunktionale Oder-Konstruktionen
    unsinn, kann weg: (?<=(\s|)), (?=(\s|)[[|\(])
    unangemessen: (\s|) besser wäre einfach \s?
    disfunktional: [[|\(] gemeint ist wohl: [\[\(]



    Wie kommts zu diesem Rückschritt? Ist das auf dem Online-RegexTester entwickelt?

    Bei meim Teil ist auch die Befehls-Referenz der Regex-Sprache mit dabei.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()