std::string in Kleinbuchstaben konvertieren
-
Eine typische Lösung des Problems in dem Vorschlag von Hume sieht so aus:
char myToUpper(char c) { return std::tolower(static_cast<unsigned char>(c)); }
-
Entschuldigt dass ich den Thread wieder aus der Versenkung hole.
Aber warum benutzt man nicht direkt std::toupper ?
std::transform(s.begin(), s.end(), s.begin(), std::toupper);
-
würde mal darauf tippen, um bei späteren änderungen, nicht den ganzen quelltext nach std::toupper durchsuchen zu müssen.
anders würde es für mich auch irgendwie keinen sinn machen
-
Bitte ein Bit schrieb:
Aber warum benutzt man nicht direkt std::toupper ?
std::transform(s.begin(), s.end(), s.begin(), std::toupper);
Probier doch einfach mal aus, was passiert, wenn du es so machst.
anti-freak schrieb:
würde mal darauf tippen, um bei späteren änderungen, nicht den ganzen quelltext nach std::toupper durchsuchen zu müssen.
anders würde es für mich auch irgendwie keinen sinn machenNein.
-
SeppJ schrieb:
anti-freak schrieb:
würde mal darauf tippen, um bei späteren änderungen, nicht den ganzen quelltext nach std::toupper durchsuchen zu müssen.
anders würde es für mich auch irgendwie keinen sinn machenNein.
sondern?
-
SeppJ schrieb:
Probier doch einfach mal aus, was passiert, wenn du es so machst.
-
Nach reichlich Testen habe ich folgendes herausgefunden:
char myToLower(char c) { return std::tolower(static_cast<unsigned char>(c)); } void Test() { //std::string S = "Hallo Welt: `!@#$%^&*()_ ['; üäöÜÄÖß<>µ "; std::string S = "üöäÜÖÄ"; std::string R1 = S; std::string R2 = S; std::transform(R1.begin(), R1.end(), R1.begin(), myToLower); // Liefert bei mir "üöäÜÖÄ" std::transform(R2.begin(), R2.end(), R2.begin(), std::tolower); // Liefert bei mir"üöäüöä" return; }
Casten ist mir immer unsympatisch und jetzt weis ich auch warum. :p
-
std::transform(R2.begin(), R2.end(), R2.begin(), std::tolower);
Das compiliert bei dir?
Da hast du nämlich Glück/Pech, denn wenn später irgendwo direkt oder indirekt locale eingebunden wird, dann wird dir das wegen der Überladung um die Ohren fliegen.
-
@SeppJ
Ja es compiliert. Ich habe aber keine Ahnung was für ein Problem du da siehst.Wenn ich in der MSDN nach transform suche, lande ich in der Doku zu collate::transform(). Aber das dürfte ja nicht das Problem sein ?
Da hast du nämlich Glück/Pech
Genau deswegen frage ich ja.
-
Ich meine die Überladung von std::tolower in der Standardbibliothek. Bind mal zusätzlich locale ein, dann wirst du sehen, was passiert.
-
SeppJ schrieb:
std::transform(R2.begin(), R2.end(), R2.begin(), std::tolower);
Das compiliert bei dir?
Da hast du nämlich Glück/Pech, denn wenn später irgendwo direkt oder indirekt locale eingebunden wird, dann wird dir das wegen der Überladung um die Ohren fliegen.
<locale> deklariert ein Funktionstemplate tolower. Im Kontext des transform-Aufrufes ist der entsprechende Templateparameter aber nicht deduzierbar. Diese Überladung kann daher nicht im Weg sein.
-
#include <algorithm> #include <cctype> #include <iostream> #include <locale> #include <string> int main() { std::string s = "Hallo, Welt. äöüÄÖÜ"; std::transform(s.begin(), s.end(), s.begin(), std::tolower); std::cout << s << '\n'; }
führt zu
foo.cc: In Funktion »int main()«: foo.cc:10:61: Fehler: keine passende Funktion für Aufruf von »transform(std::basic_string<char>::iterator, std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unaufgelöster überladener Funktionstyp>)« foo.cc:10:61: Anmerkung: Kandidaten sind: In file included from /usr/include/c++/4.7/algorithm:63:0, from foo.cc:1: /usr/include/c++/4.7/bits/stl_algo.h:4940:5: Anmerkung: template<class _IIter, class _OIter, class _UnaryOperation> _OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation) /usr/include/c++/4.7/bits/stl_algo.h:4940:5: Anmerkung: Herleitung/Ersetzung von Templateargument gescheitert: foo.cc:10:61: Anmerkung: Template-Parameter »_UnaryOperation« konnte nicht ermittelt werden In file included from /usr/include/c++/4.7/algorithm:63:0, from foo.cc:1: /usr/include/c++/4.7/bits/stl_algo.h:4977:5: Anmerkung: template<class _IIter1, class _IIter2, class _OIter, class _BinaryOperation> _OIter std::transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation) /usr/include/c++/4.7/bits/stl_algo.h:4977:5: Anmerkung: Herleitung/Ersetzung von Templateargument gescheitert: foo.cc:10:61: Anmerkung: Kandidat erwartet 5 Argumente, 4 angegeben
Mit
std::transform(s.begin(), s.end(), s.begin(), static_cast<int(*)(int)>(std::tolower));
geht es. Benutzt wird dann allerdings die C-Locale, die im Zweifel Umlaute nicht mit erschlägt. Mit C++11:
#include <algorithm> #include <cctype> #include <functional> #include <iostream> #include <locale> #include <string> int main() { std::string s = "Hallo, Welt. äöüÄÖÜ"; std::locale loc("de_DE"); std::transform(s.begin(), s.end(), s.begin(), std::bind(std::tolower<char>, std::placeholders::_1, loc)); std::cout << s << '\n'; }
Das funktioniert (unter Windows muss die Locale statt de_DE german heißen, wenn ich das richtig im Kopf habe), sofern eine iso8859-Kodierung benutzt wird. Unicode erfordert natürlich etwas anderes als eine byteweise Handhabung. C++03-Äquivalent:
std::transform(s.begin(), s.end(), s.begin(), std::bind2nd(std::ptr_fun(std::tolower<char>), loc));
-
Also bei mir compiliert nur die Variante aus dem globalen Namensraum. Wenn ich die Variante aus std:: benutze, funktioniert es nicht.
-
camper schrieb:
SeppJ schrieb:
std::transform(R2.begin(), R2.end(), R2.begin(), std::tolower);
Das compiliert bei dir?
Da hast du nämlich Glück/Pech, denn wenn später irgendwo direkt oder indirekt locale eingebunden wird, dann wird dir das wegen der Überladung um die Ohren fliegen.
<locale> deklariert ein Funktionstemplate tolower. Im Kontext des transform-Aufrufes ist der entsprechende Templateparameter aber nicht deduzierbar. Diese Überladung kann daher nicht im Weg sein.
Oh, stimmt, das ist ja ein Template. Hatte ich anders in Erinnerung. Da muss ich mal kurz nachforschen, welche Überladung hier stört. Es gibt jedenfalls ein Problem, siehe seldon.
-
seldon schrieb:
Mit C++11:
std::transform(s.begin(), s.end(), s.begin(), [&loc] (char c) { return std::tolower(c, loc); });
Ist doch viel hübscher als bind.
-
SeppJ schrieb:
camper schrieb:
SeppJ schrieb:
std::transform(R2.begin(), R2.end(), R2.begin(), std::tolower);
Das compiliert bei dir?
Da hast du nämlich Glück/Pech, denn wenn später irgendwo direkt oder indirekt locale eingebunden wird, dann wird dir das wegen der Überladung um die Ohren fliegen.
<locale> deklariert ein Funktionstemplate tolower. Im Kontext des transform-Aufrufes ist der entsprechende Templateparameter aber nicht deduzierbar. Diese Überladung kann daher nicht im Weg sein.
Oh, stimmt, das ist ja ein Template. Hatte ich anders in Erinnerung. Da muss ich mal kurz nachforschen, welche Überladung hier stört. Es gibt jedenfalls ein Problem, siehe seldon.
War doch nicht richtig, hätte noch mal nachlesen sollen
n3337 schrieb:
14.8.2.5 Deducing template arguments from a type [temp.deduct.type]
[...]
5 The non-deduced contexts are:
[...]
A function parameter for which argument deduction cannot be done because the associated function
argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply:
— more than one function matches the function parameter type (resulting in an ambiguous deduction),
or
— no function matches the function parameter type, or
— the set of functions supplied as an argument contains one or more function templates.Die Überladungen in <locale> sind also doch ein Problem.
template <typename T> void foo(T) {} template <typename F> void bar(F) {} void foo(char) {} int main() { bar(foo); // Fehler bar<void(char)>(foo); // ok }