URLdecode-Funktion - gut geschrieben?



  • Hallo zusammen,

    nach dem ich euch in der letzten Zeit immer mit Fragen zu Problemen gelöchert habe, möchte ich nun mal etwas geben und euch "nur" um eure Meinung fragen.

    Seit einigen Tagen versuche ich mit Hilfe des Internets eine URLdecode-Funktion - die mit C++-Strings arbeiten kann - zu finden. Leider habe ich nichts passendes gefunden, daher habe ich mich mal selbst daran gewagt. Anbei ein kleines Beispiel Programm. Ich würde gerne wissen was ihr davon haltet.

    #include <string>
    #include <iostream>
    using namespace std;
    
    #define ISXDIGIT(a) (((a) >= '0' && (a) <= '9') || ((a) >= 'a' && (a) <= 'f'))
    
    void URLdecode(string &myString) {
    
        int pos = 0;
        while(pos < myString.length()) {
            if (myString[pos] == '%') {
                char c1 = tolower(myString[pos+1]);
                char c2 = tolower(myString[pos+2]);
                if (ISXDIGIT(c1) && ISXDIGIT(c2)) {
                    if (c1 >= 'a' && c1 <= 'f')
                        c1 = c1 - 87;
                    if (c2 >= 'a' && c2 <= 'f')
                        c2 = c2 - 87;
                    myString[pos] = char(c1 * 16 + c2);
                    myString.erase(pos+1, 2);
                }
            }
            pos++;
        }
    }
    
    int main(int argc, char* argv[]) {
    
        string myString = "http%3A%2F%2Fwww%2Egoogle%2Ede%2F";
        //string myString = "http%3H%2G%2Fwww%2Zgoogle%2Ede%2F";
    
        cout << "Original: '" << myString << "'" << endl;
        URLdecode(myString);
        cout << "After URLdecode: '" << myString << "'" << endl;
    }
    

    Vielleicht hat jemand ja eine Idee wie man die Funktion verbessern könnte?

    lg,
    Funny



  • Hallo,

    um, was macht die URLdecode Funktion denn eigentlich?

    Was mir spontan auffällt: Wieso hast du ein Makro definiert, um auf den 'Typ' des chars zu prüfen? Es gibt doch die Funktionen der cstring, also isdigit usw.

    MfG

    GPC



  • Einmal würde ich die "if(c1<.." und "if(c2<.." zu einer Funktion zusammenfassen, zweitens bekommst du im Bereich 0..9 Probleme, weil du dort deine char-Werte nicht umrechnest. Und drittens schau dir mal string::replace() an.



  • Ich glaube dein Code funktioniert nicht mehr wenn nach dem Prozentzeichen keine 2 Zeichen mehr kommen...



  • Außerdem würde ich einen neuen String erstellen und zurückgeben lassen anstatt das Original zu modifizieren.



  • GPC schrieb:

    was macht die URLdecode Funktion denn eigentlich?

    Die Funktion wandelt einen String der URL-Encoded ist (z.B. Daten aus einem HTTP GET oder POST Request) in einen "normalen" String um.

    GPC schrieb:

    Wieso hast du ein Makro definiert, um auf den 'Typ' des chars zu prüfen? Es gibt doch die Funktionen der cstring, also isdigit usw.

    Okay, ob es ein Digit ist, kann ich damit prüfen - wusste ich nicht. Aber ich muss auch wissen ob es zwischen a und f liegt, denn hex geht ja nur bis f, also darf ein %2g nicht dekodiert werden.

    CStoll schrieb:

    Einmal würde ich die "if(c1<.." und "if(c2<.." zu einer Funktion zusammenfassen

    Wie meinst du das? Eine extra Funktion?

    CStoll schrieb:

    zweitens bekommst du im Bereich 0..9 Probleme, weil du dort deine char-Werte nicht umrechnest

    Was muss ich denn da umrechnen? 0-9 bleibt 0-9

    CStoll schrieb:

    Und drittens schau dir mal string::replace() an.

    Wie kann mir string::replace denn dort helfen? Ich müsste ja

    myString.replace(pos, 3, char(c1 * 16 + c2));
    

    aufrufen, aber damit kompiliert er bei mir nicht. Wenn ich bisher alles richtig verstanden habe ist das auch klar, denn er will an dieser Stelle ja einen const string&. Ich müsste das ja dann wie folgt machen

    string repl;
    repl = char(c1*16+c2);
    myString.replace(pos, 3, repl);
    

    Ich nehme mal an so meinst du das?

    ......... schrieb:

    Ich glaube dein Code funktioniert nicht mehr wenn nach dem Prozentzeichen keine 2 Zeichen mehr kommen...

    Oh, das ist korrekt, ist mir gar nicht aufgefallen. Dürfte sich ja schnell beheben lassen. Denke ein

    while(pos < (myString.length() - 2))
    

    sollte da reichen, oder?

    ......... schrieb:

    Außerdem würde ich einen neuen String erstellen und zurückgeben lassen anstatt das Original zu modifizieren.

    Die Aufruf des URLdecode erfolgt in meinem Projekt nur an einer Stelle und zwar wenn der Server die Daten vom Brwoser ließt und das soll möglichst schnell gehen. Nach meinem verständniss ist es versehentlich schneller das ganze per Referenz zu machen als

    myString = URLdecode(myString);
    

    denn das würde ich dann tun.

    lg,
    Funny

    Edit: Hab grad gesehen das es in der ctype.h auch ein isxdigit() gibt, sorry - hatt das überlesen, werd ich gleich mal ändern!



  • So hatte ich das früher mal geschrieben: http://www.c-plusplus.net/forum/viewtopic-var-t-is-122247-and-highlight-is-*urldecode*.html

    Aber damit war ich auch nicht ganz zufrieden und hab noch was geändert. Hab es jetzt aber verloren.

    Das - 87 in deinem Code sieht wie ein Hack aus. Ich verstehs auf jeden Fall nicht. 🤡



  • Ich habe mal was ähnliches gemacht. Zu finden in meinen cxxtools (http://www.tntnet.org/cxxtools.hms). Da parse ich Query-Parameter. Und das geht so:

    #include <string>
    #include <cxxtools/query_params.h>
    #include <iostream>
    
    int main(int argc, char* argv[])
    { 
      std::string myString = "p1=Hall%f6chen+Welt&p2=blah";
    
      cxxtools::QueryParams q;
      q.parse_url(myString);
    
      std::cout << "p1=" << q["p1"] << '\n'
                << "p2=" << q["p2"] << std::endl;
    }
    

    Der Code zum parsen findest Du in den cxxtools unter src/query_params.cpp in der template-Funktion _parse_url ganz am Anfang. Der Quelltext ist auch Online über http://www.tntnet.org/download/cxxtools-1.4.1/src/query_params.cpp aufrufbar.

    Tntnet



  • Hab mir deine Idee mal angesehen, da liegt auch der kleine Unterschied zu meiner Funktion und somit beantworte ich deinen Kommentar

    code. schrieb:

    Das - 87 in deinem Code sieht wie ein Hack aus. Ich verstehs auf jeden Fall nicht. 🤡

    auch direkt:

    Nach dem ich ein paar Sachen korrigiert habe, sieht meine Funktion nun so aus:

    void URLdecode(string &myString) {
    
        int pos = 0;
        while(pos < (myString.length() - 2)) {
            if (myString[pos] == '%') {
                char c1 = tolower(myString[pos+1]);
                char c2 = tolower(myString[pos+2]);
                if (isxdigit(c1) && isxdigit(c2)) {
                    if (c1 >= 'a' && c1 <= 'f')
                        c1 = c1 - 87;
                    else
                        c1 = c1 - 48;
                    if (c2 >= 'a' && c2 <= 'f')
                        c2 = c2 - 87;
                    else
                        c2 = c2 - 48;
                    //myString[pos] = char(c1 * 16 + c2);
                    //myString.erase(pos+1, 2);
                    string repl;
                    repl = char(c1*16+c2);
                    myString.replace(pos, 3, repl);
                }
            }
            pos++;
        }
    }
    

    Und wenn ich keinen Denkfehler habe, dann ist

    c1 = c1 - 87; identisch zu hexDigit - 'a' + 10;
    c1 = c1 - 48; identisch zu hexDigit - '0';

    Beispiel 1
    c1 = 'a' - 87 = 10 bzw. 'a' - 'a' + 10 = 10
    c1 = 97 - 87 = 10 bzw. 97 - 97 + 10 = 10

    Beispiel 2
    c1 = '0' - 48 = 0 bzw '0' - '0' = 0
    c1 = 48 - 48 = 0 bzw. 48 - 48 = 0

    Der Berechnungsweg ist ein wenig anders, aber es kommt das selbe raus. Mag vielleicht daher kommen das ich mich zusehr auf die ASCII-Tabelle (in der 'a' = 97 und '0' = 48 ist) konzentriert habe. Ich werde deine Idee aber gerne aufnehmen - sieht wesentlich besser aus *g*

    @tntnet:
    Das hört sich gut an, ich werde mir das mal ansehen. Danke 😉


Anmelden zum Antworten