Newbie: Vernünftiger Umgang mit Strings?



  • sunny31 schrieb:

    test = std::tolower(test);
    

    Ich hoffe, dass mein Beispiel funktioniert. Habe momentan kein Compiler bei mir rumliegen um das zu testen...

    Genau das war mein Problem. Das tolower() da oben scheint nicht erlaubt zu sein...

    "error: cannot convert `std::string' to `int' for argument `1' to `int tolower(int)'"



  • Ja du hast recht...

    richtig wäre es so:

    #include <iostream>
    #include <string>
    #include <cctype>
    
    int main()
    {
        std::string test = "MAX";
        for ( unsigned int i=0; i < test.size(); i++ )
               test[i]=std::tolower(test[i]);
        std::cout << test << std::endl;   //max
    }
    

    Wobei, es sicher bessere Lösungen dafür gibt...



  • versuchs mal so

    string test="Test String";
    for (int i=0;i<test.length();i++) test[i]=tolower(test[i]);
    


  • sunny31 schrieb:

    funktioniert die ToLower Funktion so:

    #include <cctype>
    #include <iostream>
    int main()
    {
        std::string test = "MAX";
        std::cout << test << std::endl; // Ausgabe: MAX
        test = std::tolower(test);
        std::cout << test << std::endl; // Ausgabe: max
        return 0;
    }
    

    Ich hoffe, dass mein Beispiel funktioniert. Habe momentan kein Compiler bei mir rumliegen um das zu testen...

    Habe es auch nicht ausprobiert, aber 1. ist es eine C-Funktion (nichts C++-artiges) und 2. konvertiert es nur einen einzelnen Charachter und keine Zeichenkette.
    Es ist sowieso blödsinnig jemanden mit C-Krüppelfunktionen anzukommen, wenn er C++ machen will. Weil man hier eigentlich eine for-Schleife bauen müsste:

    #include <cctype>
    #include <iostream>
    int main()
    {
        std::string test = "MAX";
        std::cout << test << std::endl; // Ausgabe: MAX
        for(size_t i = 0; i<test.size(); i++)
              test[i] = std::tolower(test[i]);
        std::cout << test << std::endl; // Ausgabe: max
        return 0;
    }
    

    Aber sowas findet man fertig in der Boost-String-Algo-Lib.



  • So, wenn man kein Boost nutzen will:

    #include <cctype>
    
    void to_lower(string &str)
    {
        for(size_t i = 0; i<str.size(); ++i)
              str[i] = std::tolower(str[i]);
    }
    

    Aber Boost ist hier eindeutig lohnenswert, da es nicht nur mit std::string zusammen arbeitet und auch die Locale beachtet!



  • Dafür kann man aber die Funktion 'std::transform' benutzen, jedoch gibt es dabei auch ein paar Fallstricke (je nach Compiler) zu beachten, s. http://www.c-plusplus.net/forum/viewtopic-var-t-is-210176-and-highlight-is-transform+tolower.html



  • Danke allerseits... Zwischenfazit bzgl. Lowercase/Uppercase: Rein auf STL-Ebene macht man es wohl tatsächlich selbst, also eine Schleife über ein Char-Array...
    Zwischenfazit2: Boost muß her. Ich will nämlich langsam Ergebnisse sehen. Und damit den Ansporn aufbauen, mich dann auch Standard-näher schlau zu machen.



  • Ich habe mal eine Nachfrage. Das ist aus boosts "to_lower" (boost::algorithm::to_lower). Ich habe oft Probleme, die Funktionenbeschreibungen zu verstehen. Ich weiß dann nicht, welche Argumente von welchem Typ verlangt werden und wie die Rückgabe aussieht...

    [http://www.boost.org/doc/libs/1_40_0/doc/html/boost/algorithm/to_lower.html]

    void to_lower(WritableRangeT & Input, 
                    const std::locale & Loc = std::locale());
    

    "void to_lower". OK, void sagt mir AFAIK "keine Rückgabe". Die Funktion ändert den String direkt. In der Klammer sollte m.E. das Argument stehen. Nur was heißt das darin? Kann mir das jemand erklären? Ich sehe ein Komma, würde also 2 Argumente vermuten. Aber warum 2?



  • Man sollte auch nicht unbedingt tolower aus <ctype> benutzen, sondern besser tolower aus <locale> .
    Irgendwie so:

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <locale>
    
    template<typename charT>
    class ToLower
    {
    public:
        ToLower(char const * locale = "")
            : loc(locale)
        { }
        charT operator()(charT c){ return std::tolower(c, loc); }
    private:
        std::locale loc;
    };
    
    int main()
    {
        std::string hallo = "haLLo wELt";
        std::transform(hallo.begin(), hallo.end(), hallo.begin(), ToLower<std::string::value_type>());
        std::cout << hallo << '\n';
    }
    


  • #include <algorithm>
    #include <string>

    std::string test = "THIS IS MY STRING";
    std::transform(test.begin(), test.end(), test.begin(), std::tolower);

    So gehts wohl am besten und am schönsten.



  • Squeller schrieb:

    "void to_lower". OK, void sagt mir AFAIK "keine Rückgabe". Die Funktion ändert den String direkt.

    Ja. Wenn du eine Kopie haben willst, schau dir to_lower_copy() an.

    Squeller schrieb:

    In der Klammer sollte m.E. das Argument stehen. Nur was heißt das darin? Kann mir das jemand erklären? Ich sehe ein Komma, würde also 2 Argumente vermuten. Aber warum 2?

    Das erste für den zu bearbeitenden String und das zweite für das Locale. Das Locale bestimmt zum Beispiel, welche speziellen Zeichen berücksichtigt werden, also 'ä' in der deutschen und 'é' in der französischen Sprache.



  • Squeller schrieb:

    [http://www.boost.org/doc/libs/1_40_0/doc/html/boost/algorithm/to_lower.html]

    void to_lower(WritableRangeT & Input, 
                    const std::locale & Loc = std::locale());
    

    "void to_lower". OK, void sagt mir AFAIK "keine Rückgabe". Die Funktion ändert den String direkt. In der Klammer sollte m.E. das Argument stehen. Nur was heißt das darin? Kann mir das jemand erklären? Ich sehe ein Komma, würde also 2 Argumente vermuten. Aber warum 2?

    Unter Description stehen ja die Bedeutungen der einzelnen Parameter:

    Input A range
    Loc a locale used for conversion

    Wobei du den zweiten Wert nicht explizit angeben mußt, weil der zweite Parameter einen Default-Wert vorgibt:

    void to_lower(WritableRangeT & Input, const std::locale & Loc = std::locale());

    Nur wenn dir der Default-Wert std::locale() nicht zusagt, gibst du beim Aufruf einen anderen an. In den meisten Fällen dürfte aber std::locale() i.O. sein, da sich dieses nach den Betriebssystem-Einstellungen richtet. Was die Locale ist, weißt Du? Das hat was mit den Zeichencodes für verschiedene Länder und Sprachen zu tun, siehe hier:

    http://www.cplusplus.com/reference/std/locale/



  • Vielen Dank für die Antwort.

    Nein, was eine locale ist, habe ich auch nur erahnt... Wie ist das "&" zu verstehen? Hat das was mit Standardwerten zu tun? Mein Problem ist wohl die Komplexität des Ausdrucks. Wenn da jetzt stünde "void ziehbvonaab(int a, int b)" dann ginge es ja...

    Ebenso weiß ich noch nicht, wie "WritableRangeT & Input" zu verstehen ist, was ist hier der Datentyp?



  • Ja, für einen C++-Neuling sind in der Funktionssignatur tatsächlich viele Features drin. C++ ist komplex (nicht kompliziert!), und man muß viel lernen. Aber das ist alles erlernbar und keine Magie! 😉 Wichtig ist sich die gesamte Funktions-Signatur anzuschauen:

    template<typename WritableRangeT> // Funktion to_lower erwartet einen genauen Typnamen!!!
    void to_lower(WritableRangeT & Input,
                                          const std::locale & Loc = std::locale());
    

    Du mußt als erstes lernen was Templates sind, um WritableRangeT zu verstehen. Bei Templates handelt es sich "nur" um Codeschablonen, die erst zur Compilezeit typisiert werden. Grob gesagt kann WritableRangeT jeder Typ sein, mit dem das Template "kompatibel" ist. Range deutet darauf hin, das es ein Array, String, Vector etc. sein kann. Der vollständige Aufruf müsste so lauten:

    string s("HaLLo!");
    to_lower<string>(s);     // mit <string> typisiere ich WritableRangeT bzw. das Template
    

    So weiß die Funktion, das s ein String-Objekt ist. Aber da bei solchen einfachen Funktionen der Compiler aus dem übergebenen Wert "s" den Typ string selber feststellen kann, muß man das nicht angeben.

    string s("HaLLo!");
    to_lower(s);     // <string> setzt der Compiler selbst ein... implizite Typisierung
    

    Der Vorteil von Templates ist, das man Code für verschiedenen Typen benutzen kann. Und man spart sich Copy&Paste in seinem Code. D.h. to_lower kann auch mit Arrays, Vector usw. arbeiten.

    Das & steht für By-Reference, also das die Funktion mit dem "original" Objekt arbeitet bzw. dieses manipulieren wird. Weitere Infos gibt es unter http://www.kharchi.eu/wiki/doku.php?id=cpp:std:reference.

    Hast du ein vernünftiges C++-Buch, in dem solche Dinge ausführlich und vor allem verständlich erklärt werden? Weil für C++ kommt man mit Try & Error nicht schnell vor ran.





  • Artchi schrieb:

    Du mußt als erstes lernen was Templates sind, um WritableRangeT zu verstehen. Bei Templates handelt es sich "nur" um Codeschablonen, die erst zur Compilezeit typisiert werden. Grob gesagt kann WritableRangeT jeder Typ sein, mit dem das Template "kompatibel" ist. Range deutet darauf hin, das es ein Array, String, Vector etc. sein kann. Der vollständige Aufruf müsste so lauten:

    string s("HaLLo!");
    to_lower<string>(s);     // mit <string> typisiere ich WritableRangeT bzw. das Template
    

    So weiß die Funktion, das s ein String-Objekt ist. Aber da bei solchen einfachen Funktionen der Compiler aus dem übergebenen Wert "s" den Typ string selber feststellen kann, muß man das nicht angeben.

    string s("HaLLo!");
    to_lower(s);     // <string> setzt der Compiler selbst ein... implizite Typisierung
    

    Der Vorteil von Templates ist, das man Code für verschiedenen Typen benutzen kann. Und man spart sich Copy&Paste in seinem Code. D.h. to_lower kann auch mit Arrays, Vector usw. arbeiten.

    Also, geht es darum, dass ich a) einer Funktion dann unterschiedliche, sinnvolle Typen übergeben kann und b) je nach Eingabetyp in der Funktion handeln kann? Bspw. könnte eine Funktion sowohl ein Char-Array als auch einen String bekommen?

    Und irgendwas habe ich doch sicher übersehen: an so einer Funktionssignatur "..(WritableRangeT ...) sehe ich doch gar nicht, welche(r) Typ(en) denn nun erlaubt sind?

    Das & steht für By-Reference, also das die Funktion mit dem "original" Objekt arbeitet bzw. dieses manipulieren wird. Weitere Infos gibt es unter http://www.kharchi.eu/wiki/doku.php?id=cpp:std:reference.

    Hast du ein vernünftiges C++-Buch, in dem solche Dinge ausführlich und vor allem verständlich erklärt werden? Weil für C++ kommt man mit Try & Error nicht schnell vor ran.

    Ja, habe ein Buch von Dirk Louis. Muss ich nochmal lesen, ich glaube da stand etwas in der Zeiger-Ecke, eine Giftküche, an der ich schnell vorbeigelesen hatte. 😃



  • ganz ehrlich, merkt ihr es noch? er will einen string per tolower umwandeln und bekommt templates, boost oder qt vorgesetzt. Irgendwas stimmt da doch ganz gewaltig nicht...



  • Wenn er auf Boost verzichten will, kann er doch die, ein paar Seiten weiter vorne gepostete, einfache und funktionierende Lösung verwenden:

    #include <algorithm>
    #include <string>
    
    std::string test = "THIS IS MY STRING";
    std::transform(test.begin(), test.end(), test.begin(), std::tolower);
    


  • jaja schrieb:

    ganz ehrlich, merkt ihr es noch? er will einen string per tolower umwandeln und bekommt templates, boost oder qt vorgesetzt. Irgendwas stimmt da doch ganz gewaltig nicht...

    C++ ... kompliziertes Denken ... irgendwas war da.



  • jaja schrieb:

    ganz ehrlich, merkt ihr es noch? er will einen string per tolower umwandeln und bekommt templates, boost oder qt vorgesetzt. Irgendwas stimmt da doch ganz gewaltig nicht...

    Vielleicht hast du nichts bemerkt, aber es geht hier in diesem Topic schon laaange nicht mehr um "Wie mache ich Zeichen klein?". Es geht hier mittlerweile um C++-Syntax und -Features, am Beispiel von to_lower. Es könnte aber auch jede andere Funktion aus C++ sein! Er hätte bei jeder anderen C++-Funktion die gleichen Fragen gestellt. Er lernt noch C++, das hat nichts mit Boost oder so zu tun. Wer kein C++ kann, wird nun mal solche Fragen stellen. Das er noch kein C++ kann, kann ja wohl C++ oder Boost nichts für.


Anmelden zum Antworten