Komplexes Suchen/Ersetzen in einem AnsiString, geht das überhaupt?



  • Hallo alle!

    Nochmals herzlichen Dank an alle für eure Mühe!

    Auch wenns mir etwas peinlich ist, aber ich habe es noch nicht hingekriegt, bin aber noch weiter am experimentieren.

    @chronol
    Leider sind die Daten nach Anwendung der Funktion nicht mehr konsistent. 😞

    @audacia
    Die Kurzfassung mittels regulären Audrücken scheitert tatsächlich daran, dass TPerlRegEx nicht unter BCB4 funktioniert, zumindest wüsste ich nicht wie sich die Komponente installieren lässt, wobei meine Version 4 ja auch schon steinzeitlich ist. Anscheinend basiert die Komponente auf Perl, könnte man dann vielleicht den Ersetzungsvorgang irgendwie "outsourcen" an ein entsprechendes Perl-Skript das mit regulären Audrücken umgehen kann?

    Habe mich mal nach aktuellen C++ Builder Versionen erkundigt und hatte einen Preisschock, so was leistet man sich doch nicht als Student und Gelegenheitsprogrammierer, warum gibts da keine Einsteigerversion mit zumutbarem Preis und beschränktem Funktionsumfang für die nichtkommerzielle Nutzung? Ok, das ist jetzt etwas offtopic.

    @Deforation
    Die lange ausführliche Lösung (danke vielmals für die Arbeit!!) konnte ich nicht kompilieren, weil der Compiler eine ganze Liste von Fehlern meldet, die aber wohl einfach damit zusammenhängen, dass ein Teil der Funktionen (und Bibliotheken?) in meiner alten BCB Version nicht existieren. Ich versuche nun entsprechende Stellen umzuschreiben, bzw. die Logik zu übersetzen, wobei ich wirklich Anfänger bin und ich die Syntax und Funktionen teilweise gar nicht verstehe. (Trotz vorbildlicher Doku.) Bleibe aber an der Sache dran.

    Was soll an w_str() nicht in Ordnung sein, das habe ich nicht mitbekommen?

    Viele Grüsse



  • lichtmagie schrieb:

    @chronol
    Leider sind die Daten nach Anwendung der Funktion nicht mehr konsistent. 😞

    StringReplace ist, wie ich sagte, hierfür leider ungeeignet.

    lichtmagie schrieb:

    @audacia
    Die Kurzfassung mittels regulären Audrücken scheitert tatsächlich daran, dass TPerlRegEx nicht unter BCB4 funktioniert, zumindest wüsste ich nicht wie sich die Komponente installieren lässt, wobei meine Version 4 ja auch schon steinzeitlich ist.

    Das kann man so sagen. Es ist ohnehin höchste Zeit für ein Upgrade, wenn du mich fragst.

    lichtmagie schrieb:

    Anscheinend basiert die Komponente auf Perl, könnte man dann vielleicht den Ersetzungsvorgang irgendwie "outsourcen" an ein entsprechendes Perl-Skript das mit regulären Audrücken umgehen kann?

    Die Komponente heißt so, weil sie PCRE (Perl Compatible Regular Expressions) benutzt. Doku dazu hier.

    C++Builder 4 habe ich nicht, aber beim C++Builder 6 ist PCRE mitgeliefert. Schau einfach mal nach, ob pcre.h bei dir im Include-Verzeichnis liegt. Falls nicht, lade eben PCRE herunter.

    lichtmagie schrieb:

    als Student und Gelegenheitsprogrammierer

    ... kann man die SSL-Versionen zu moderateren Preisen beziehen.

    lichtmagie schrieb:

    warum gibts da keine Einsteigerversion mit zumutbarem Preis und beschränktem Funktionsumfang für die nichtkommerzielle Nutzung?

    Das gab es in der Vergangenheit mehrfach, und es wird gerade auch in den Delphi-Newsgroups diskutiert. Hier ein offizielles Statement (der Rest des Threads ist auch lesenswert).

    lichtmagie schrieb:

    Was soll an w_str() nicht in Ordnung sein, das habe ich nicht mitbekommen?

    http://edn.embarcadero.com/article/38475#13UnicodeStringtstrNarrowsWideData
    https://forums.codegear.com/thread.jspa?threadID=6426



  • Entgegen audacias Meinung ist StringReplace durchaus geeignet.
    In deinem Fall müsstest du halt sehen, wo es genau hängt.
    Ohne genaue Kenntniss des Aufbaus deines Strings ist das kaum möglich.



  • chronol schrieb:

    Entgegen audacias Meinung ist StringReplace durchaus geeignet.

    Ich habe noch keine StringReplace()-basierte Lösung gesehen, die GENAU das Pattern "N??,0;N,24;N??,0;N,24;N??,0;N,24;N126,0;N,24;" durch "N??,0;N,32;N??,0;N,32;N??,0;N,32;" ersetzt. (Die einzige neben der Regex-basierten Lösung als potentiell brauchbar einzustufende ist die von Deforation, der anscheinend gerne das Rad neu erfindet 😉 und außerdem auf StringReplace() verzichtet).

    Wie dem auch sei, hier ist eine kleine triviale Wrapperklasse für PCRE, die die Grundfunktionen (Match und Replace) erfüllt. Damit reduziert sich die Komplexität der Regex-Lösung auf zwei Zeilen:

    String performReplace (String input)
    {
        RegEx re ("N(.{2}),0;N,24;N(.{2}),0;N,24;N(.{2}),0;N,24;N126,0;N,24;");
        return re.replaceAll (input, "N\\1,0;N,32;N\\2,0;N,32;N\\3,0;N,32;");
    }
    

    Funktioniert wie gewünscht, ganz ohne "genaue Kenntnis des Aufbaus deines Strings".

    Jetzt bitte dasselbe einmal mit StringReplace().



  • Es scheint, als wäre die Lösung so nah wie nie zu vor! 🙂

    Aber ich erhalte noch folgende Fehlermeldung:

    [Linker Fehler] Unresolved external '_pcre_free' referenced from C:\PROGRAMME\BORLAND\EIGENE PROJEKTE\PROJEKT.OBJ.

    Die "pcre.h" war schon vorhanden, also habe ich diese inkludiert plus zusätzlich habe ich regex.hpp und regex.cpp heruntergeladen und ebenfalls inkludiert.

    Doch im Zusammenhang mit dem Aufruf der Funktion performReplace() kommt dann die obige Fehlermeldung...



  • Ich habe noch keine StringReplace()-basierte Lösung gesehen, die GENAU das Pattern "N??,0;N,24;N??,0;N,24;N??,0;N,24;N126,0;N,24;" durch "N??,0;N,32;N??,0;N,32;N??,0;N,32;" ersetzt.
    

    Dann müsstest du halt etwas zurückblättern ... 😉



  • Jetzt bitte dasselbe einmal mit StringReplace().

    Die leicht bereinigte Version...

    String replace(String source)
    {
       String sf="N126,0;N,24;";
       int pos=source.Pos(sf);
       int start;
       int Nc;
       while(pos>0)
       {
          start=pos;
          Nc=6;
          while(start&&Nc)
          {
             if(source[--start]=='N')
             {
                Nc--;
             }
          }
          String repl=source.SubString(start,pos-start);
          repl=StringReplace(repl,"N,24","N,32",TReplaceFlags() << rfReplaceAll);
          source.Delete(start,pos-start+sf.Length());
          source.Insert(repl,start);
          pos=source.Pos(sf);
       }
       return source;
    }
    


  • chronol schrieb:

    Die leicht bereinigte Version...

    ... erfüllt nicht ihren Zweck.

    Dein Konstrukt ersetzt beispielsweise auch "N??,0;N,128;N??,0;N,24;N??,0;N,24;N,31;N126,0;N,24;" durch "N??,0;N,128;N??,0;N,32;N??,0;N,32;N,31;", was nicht erwünscht ist. Und wenn ich es mit "N126,0;N,24;N126,0;N,24;" füttere, fliegt eine Exception.

    Es ist schlicht fahrlässig, für eine derart präzise gestellte Aufgabe mit Bruteforce-Techniken wie StringReplace() heranzugehen, ganz abgesehen davon natürlich, daß es offensichtlich überaus fehleranfällig ist. Reguläre Ausdrücke sind die richtige Lösung.

    lichtmagie schrieb:

    Aber ich erhalte noch folgende Fehlermeldung:

    [Linker Fehler] Unresolved external '_pcre_free' referenced from C:\PROGRAMME\BORLAND\EIGENE PROJEKTE\PROJEKT.OBJ.

    Linkst du gegen die dynamische RTL? Falls ja, sieh mal nach (mit Dependency Walker), ob die DLL das Symbol exportiert.

    Wenn du es nicht hinbekommst, kannst du auch einfach std::free() stattdessen verwenden; die PCRE-Allokationsfunktionen leiten Aufrufe standardmäßig an std::malloc() und std::free() weiter. Allerdings solltest du in regex.cpp dann in einem Kommentar auf den Workaround hinweisen.



  • Jaaaa! Es funktioniert! Danke. Habe zwar nicht alles verstanden was du geschrieben hast, aber habe in der regex.cpp "pcre_free (rex);" durch "free (rex);" ersetzt, das hast du wohl auch so gemeint und jetzt funktionierts!

    Danke nochmals an alle!


Anmelden zum Antworten