Andreas Dölling: RegExp-Problem für Glossar gelöst

Hallo,

für alle, die es interessiert:
wir haben unter http://forum.de.selfhtml.org/?t=100676&m=617171 ein Performance-Problem diskutiert, das sich eindeutig auf den exzessiven Einsatz von komplexen regulären Ausdrücken zurückführen ließ.

Ich habe das Script jetzt an einigen neuralgischen Punkten ein wenig verändert und konnte auf diese Weise die Performance erheblich steigern - so sehr, daß man das Script jetzt einsetzen kann!

Vorher wurde der reguläre Ausdruck zu jedem Glossarbegriff immer wieder on the fly als neues Objekt angelegt, also beim Durchlaufen von sagen wir mal 10 Textknoten im HTML-Dokument jeweils 10 mal. Das ist natürlich Unfug. Daher wird der reguläre Ausdruck zu jedem Glossarbegriff nun vor dem Durchlaufen der Knoten des HTML-Dokuments einmal angelegt und dann immer wieder benutzt.

Den eigentlichen Performance-Gewinn brachte aber, daß ich jetzt der Ausführung des regulären Ausdrucks auf einen Textknoten immer einen groben Vorabtest vorgeschaltet habe, der prüft, ob der jeweilige Glossargebriff überhaupt in irgendeiner Form im Knoten vorkommt. Dieser Vorabtest ist natürlich dann ein entsprechend einfacher und schneller RegExp. Und nur wenn dieser Ausdruck matcht, wird der eigentliche komplexe Ausdruck angewendet.

Das Ganze sieht dann so aus:
for(k=0; k<glossary.length; k++) {
   var tmpRegExp = new RegExp(glossary[k]["term"], "ig");
   if(!tmpRegExp.test(parentObj.childNodes[i].nodeValue)) continue;
   var matched = glossary[k]["regexp"].exec(parentObj.childNodes[i].nodeValue);
   if(matched) {
      var preText = document.createTextNode(matched[1]);
      var postText = document.createTextNode(matched[3]);
      var dfnText = document.createTextNode(matched[2]);
      var dfnNode = document.createElement("DFN");
// ...etc.

Damit läuft es jetzt wie geschmiert, bei weiterhin vollem Leistungsumfang, wobei erstaunlicherweise festzustellen ist, daß der IE bei sehr großen HTML-Seiten deutlich schneller ist als der Firefox.

Grundsätzlich bleibt aber trotz der oben skizzierten Lösung festzuhalten, daß derartige Funktionalitäten serverseitig wohl doch besser aufgehoben sind.
;)

Danke an alle, die mitdiskutiert haben!

Ciao,
Andreas

  1. Hallo, Andreas!

    für alle, die es interessiert:
    wir haben unter http://forum.de.selfhtml.org/?t=100676&m=617171 ein Performance-Problem diskutiert, das sich eindeutig auf den exzessiven Einsatz von komplexen regulären Ausdrücken zurückführen ließ.

    dann hätte dieser beitrag wohl auch in diesen tread gehört, da der noch nicht im archiv verschwunden ist. denk beim nächsten mal bitte daran. :-)

    Ich habe das Script jetzt an einigen neuralgischen Punkten ein wenig verändert und konnte auf diese Weise die Performance erheblich steigern - so sehr, daß man das Script jetzt einsetzen kann!

    dann würde einige von uns sicherlich der quellcode dazu interessieren, damit wir alle davon lernen können. schliesslich basiert das ganze forum darauf, dass leute ihr wissen weitergeben.

    freundl. Grüsse aus Berlin, Raik

    1. Im Gegensatz zu vielen Leuten, auf die ich in diversen Foren zu verschiedenen Technologien getroffen bin, habe ich es für sinnvoll gehalten, meinen Lösungsansatz hier zu skizzieren.
      Dies ist meine Art und Weise, mich den Leuten gegenüber erkenntlich zu zeigen, die versucht haben, mir zu helfen.
      Und da ich annahm, daß die grundsätzliche Problematik vielleicht auch für andere Leute interessant ist, habe ich meine Lösung nicht im ursprünglichen Thread beschrieben, zumal jener mittlerweile recht weit unten in der Liste sitzt.

      Viele andere Leute lassen nie wieder von sich hören, wenn ihr Problem gelöst ist, so daß auch niemand an der Lösung teilhaben kann. Oftmals liest man nur ein lapidares "alles klar - habs gefunden - funzt jetzt".
      Das bringt ein Forum nicht weiter.

      Was mich auch oft in Foren stört, das ist diese Anspruchsmentalität (meistens bei Fragenden), alles schön vorgekaut als (kopierbaren) Code serviert zu bekommen.
      In vielen Fällen ist der konkrete Code notwendig, um das Problem zu beschreiben und den anderen Forumsteilnehmern bei der Suche nach Lösungsansätzen zu helfen.
      Es gibt aber auch viele Fälle, in denen es sinnvoller ist, ein Problem möglichst genau zu schildern, als zig Zeilen Code zu veröffentlichen, für deren Verständnis man meistens länger braucht und die oftmals auch noch vom Kern des Problems ablenken.
      Ich bin der Auffassung, daß Interessierte meinem Beitrag und dem ursprünglichen Thread sehr viele nützliche Informationen entnehmen können.

      Und noch einmal: ich habe eine letztlich von mir selbst erarbeitete Lösung zu einem früher in diesem Forum diskutierten Problem freiwillig hier beschrieben.
      Sollte das gegen irgendwelche Regeln verstoßen, dann tut es mir leid.
      ;)

      Andreas

      1. hi,

        Und noch einmal: ich habe eine letztlich von mir selbst erarbeitete Lösung zu einem früher in diesem Forum diskutierten Problem freiwillig hier beschrieben.

        wo wäre das problem gewesen, diese auch dort zu präsentieren?
        jemand, der jetzt im archiv irgendwann mal auf deine _frage_ stößt, findet die anderswo abgelegte _antwort_ jetzt trotzdem nicht gleichzeitig.

        gruß,
        wahsaga

        --
        "Look, that's why there's rules, understand? So that you _think_ before you break 'em."
        1. wo wäre das problem gewesen, diese auch dort zu präsentieren?
          jemand, der jetzt im archiv irgendwann mal auf deine _frage_ stößt, findet die anderswo abgelegte _antwort_ jetzt trotzdem nicht gleichzeitig.

          So gesehen habt Ihr beide natürlich recht.
          Vielleicht kann der Admin diesen Thread ja verschieben. Er möge mir verzeihen.

          Ciao,
          Andreas

      2. Hallo, Andreas!

        ... habe ich meine Lösung nicht im ursprünglichen Thread beschrieben, zumal jener mittlerweile recht weit unten in der Liste sitzt.

        ... was mit anderen worten heisst, dass du noch die möglichkeit gehabt hättest, diese antwort da einzufügen, wo sie andere leute hinterher im archiv auch finden. jetzt ist es wohl ehr glückssache, ob jemand im archiv _beide_ treads findet.
        und die leute, die in diesem ursprungstread geantwortet haben, werden wohl auch sicher ehr dort nach antworten sehen, als in einem extra tread. weil du jetzt einen neuen tread aufgemacht hast, sind jetzt 20 andere treads schneller "recht weit unten in der Liste", was andere auch wieder dazu bewegen könnte, ihrerseits neue treads zu ihrem thema aufzumachen .... also eine lawine ohne ende ...

        ...
        Sollte das gegen irgendwelche Regeln verstoßen, dann tut es mir leid.

        nein, es verstösst nicht. ;-)
        das ist natürlich immer ein zweischneidiges schwert, den completten code zu posten, oder nur teile davon.
        einerseits lernen leute, die ihn dann einfach kopieren können, damit nichts daraus,
        andererseits kenne ich mich mit javascript aus und würde mir nur viel arbeit ersparen, wenn ich eine solche lösung nicht selber austüfteln müsste. ich hätte im moment nicht mal eine konkrete verwendung für den code, finde es aber trotzdem immer sehr interessant, mir sowas anzusehen und nachzuvollziehen, weil man dabei immer wieder etwas lernen kann.

        letzten endes ist es eine frage des eigenen interesses, ob man aus fremdem code etwas lernen will, oder ihn einfach nur benutzt. den code nicht zu posten, verhindert also nur, dass leute, die das wollen, daraus etwas lernen können (was jetzt aber kein wink mit dem zaunpfahl sein soll).

        freundl. Grüsse aus Berlin, Raik

        1. ... was mit anderen worten heisst, dass du noch die möglichkeit gehabt hättest, diese antwort da einzufügen, wo sie andere leute hinterher im archiv auch finden. jetzt ist es wohl ehr glückssache, ob jemand im archiv _beide_ treads findet.
          und die leute, die in diesem ursprungstread geantwortet haben, werden wohl auch sicher ehr dort nach antworten sehen, als in einem extra tread. weil du jetzt einen neuen tread aufgemacht hast, sind jetzt 20 andere treads schneller "recht weit unten in der Liste", was andere auch wieder dazu bewegen könnte, ihrerseits neue treads zu ihrem thema aufzumachen .... also eine lawine ohne ende ...

          Hallo Raik,

          habe den Admin des Forums gebeten, diesen Thread, falls möglich, in den älteren Ursprungsthread zu verschieben.

          Zur Info noch für die Interessierten: mir ist aufgefallen, daß ich den eigentlichen regulären Ausdruck, um den es ja ging, gar nicht gepostet hatte.
          Voilà:

          // Use this function to set initial values, e.g. the HTML node which is used as starting
          // node for markGlossaryTerms().
          function initGlossary() {
             for(k=0; k<glossary.length; k++) {
                glossary[k]["regexp"] = new RegExp("((?:\n|.)*?\b)("+glossary[k]["term"]+"(?:en|s|er|e|n)?\S*)(\b(?:\n|.)*)", "ig");
             }
             if(document.getElementById("space")) {
                var myObj = document.getElementById("space");
                markGlossaryTerms(myObj);
             }
          }

          Ciao,
          Andreas

      3. Hallo Andreas,

        Und noch einmal: ich habe eine letztlich von mir selbst erarbeitete Lösung zu einem früher in diesem Forum diskutierten Problem freiwillig hier beschrieben.

        Wunderbar, danke. Du bist eine seltene positive Ausnahme und darfst dich kopfgekrault fühlen. ;-)

        Sollte das gegen irgendwelche Regeln verstoßen, dann tut es mir leid.

        Jain, es ist nur so, dass jemand, der das gleiche Problem hat im alten Thread nicht auf die Lösung hingewiesen wird. Ich habe das ergänzt: https://forum.selfhtml.org/?t=100676&m=617863.

        Grüße,
         Roland

  2. Hallo,

    (...) Dieser Vorabtest ist natürlich dann ein entsprechend einfacher und schneller RegExp. Und nur wenn dieser Ausdruck matcht, wird der eigentliche komplexe Ausdruck angewendet.

    Das Ganze sieht dann so aus:
    for(k=0; k<glossary.length; k++) {
       var tmpRegExp = new RegExp(glossary[k]["term"], "ig");

    Sehe ich es richtig, dass du bei jedem Bearbeiten eines Knotens für alle Wörter im Glossar immer neue RegExp-Objekte erzeugst? Wieso erstellst du sie nicht alle einmal am Anfang und hängst sie an das Objekt-Arrayelement an, so wie beim term-(String)Objekt, sodass du immer wieder darauf zugreifen kannst?

    if(!tmpRegExp.test(parentObj.childNodes[i].nodeValue)) continue;

    Wenn du nur Wörter finden willst, wird der Ausdruck wohl nicht mehr als /Wort/ beinhalten. Dann würde auch indexOf() ausreichen und du bräuchtest auch für den folgenden Schritt keine regulären Ausdrücke.

    var matched = glossary[k]["regexp"].exec(parentObj.childNodes[i].nodeValue);

    Mathias