Merkwürdigkeiten bei STL::MAP -Erklärung und Hilfe benötigt :)
-
otze schrieb:
struct lexicalCompare { bool operator()(const string& s1, const string& s2) const { //jetzt wirds ätzend const std::collate<char>& cmp=std::use_facet<std::collate<char> >(std::locale()); return cmp.compare(s1.data(),s1.data()+s1.size(),s2.data(),s2.data()+s2.size())<0; } };danke aber deine funktionsobjekt macht das gleiche wie mein
typedef std::map<string, string, std::less<string>> StringMap;von der stl.
ich möchte das das grosse A und das kleine a genauso behandelt werden.
als beispiel:
ich habe diese wörter in der txt-datei:Arbeit
Besen
Leben
argwöhnisch
bösartig
Lebennach Ascii wird es so sortiert, also nach meiner genauso wie nach deiner variante:
Arbeit Besen Leben argwöhnisch bösartig lieblichd.h. erst die grossen buchstaben dann die kleinen buchstaben:
ich möchte aber:
Arbeit
argwöhnisch
Besen
bösartig
Leben
lieblich
garnet so einfach
hmmm irgendwie muss man wohl, eventuell die operatoren > < überladen . vielleicht gehts dann frag mich nur wie? hmmm.ps. und das problem geht weiter ! "umlaute äöü...!" die muüssen auch richtig sortiert werden (meine umschalttaste klemmt (bin nur zu faul *gg)also nicht wundern warum alles klein geschrieben ist )
-
hmm ... std::transform(string.begin(), string.end(), string.begin(), std::tolower); ... dann sortieren ...
-
Sortieren von "transformierten" Strings mit std::less sollte dasselbe Ergebnis liefern wie Sortieren der "nicht transformierten" Strings mit std::collate::compare.
Zumindest wenn ich das richtig verstanden habe.
-
(D)Evil schrieb:
hmm ... std::transform(string.begin(), string.end(), string.begin(), std::tolower); ... dann sortieren ...
ich glaube std::transform kann man nicht anwenden bei maps

ich hab die codezeile zwischen 65 und 66 eingefügtstd::transform(Ger_wordPairs.begin(), Ger_wordPairs.end(), Ger_wordPairs.begin(), std::tolower);gibt 12 fehlermeldungen u.a
fehlermeldung:error C2780: '`global namespace'::std::_Enable_if<!std::_Is_checked_iterator<_OutIt>::_Result||!std::_Is_checked_iterator<_OutIt>::_Result,_OutIt>::_Result std::transform(_InIt1,_InIt1,_InIt2,_OutIt,_Fn2)': Erwartet 5 Argumente - 4 unterstützt c:\programme\microsoft visual studio 8\vc\include\algorithm(867): Siehe Deklaration von 'std::transform'ich glaube ausserdem würde dann alles kleingeschrieben sein oder?. is ja auch nicht Sinnvoll... hmmm
-
okay ich habs gefunden : das grösste problem gelöst hippie , danke ohne euch wär ich wohl net drauf gekommen .. jetzt gibt es nur noch ein problem´chen siehe unten
struct ignorecase { std::locale loc; bool operator()(const string& s1, const string& s2) const { string::const_iterator iter1 = s1.begin(); string::const_iterator iter2 = s2.begin(); while ((iter1!=s1.end()) && (iter2!=s2.end())) { // tolower aus locale. Beruecksichtigt die // landesspezifischen Umwandlungen char cs1 = std::tolower(*iter1,loc); char cs2 = std::tolower(*iter2,loc); if (cs1<cs2) return true; if (cs1>cs2) return false; ++iter1; ++iter2; } return false; } };und dann mit
typedef std::map<string, string, ignorecase> StringMap;so jetzt gibt es nur noch das problem mit dem Umlauten die soll er auch locker floggig sortieren nach lexikon. Im moment sortiert er erst die ä und dann erst a
beispiel:ärgern Arbeitnormalerweise sollte erst Arbeit dann ärgern kommen.
wenn jemand ne idee hat ..wobei auf console wird das zeichen wg. zeicheninkomp. nicht richtig dargestellt
gibs wohl keine lösung dafür
-
Vermutlich mußt du das tolower() noch mit dem collate<>-Ansatz von oben zusammenfassen, um die Sonderzeichen mit in die Suchfolge einzubinden.
-
jep, nun brauchst du collate. allerdings musst du beachten, dass collate sich nach der region richtet, in der du lebst, bzw die bei deinem betriebssystem angegeben ist. Es kann sein, dass du je nach pc unterschiedliche Ergebnisse bekommst, aber es ist dann immer für die region richtig(unterschiedliche Länder, unterschiedliche Arten zu sortieren)
-
CStoll schrieb:
Vermutlich mußt du das tolower() noch mit dem collate<>-Ansatz von oben zusammenfassen, um die Sonderzeichen mit in die Suchfolge einzubinden.

wie das ?
std::collate<char> cs1 = std::tolower(*iter1,loc); oder dergleichen .. ?? geht nicht..kenn die grammatik und wirkung von std::collate nicht
-
collate() wandelt den String in etwas um, was nach den gängigen Regeln deiner Sprache sortiert werden kann (was insbesondere bedeutet, daß Umlaute ins Alphabet einsortiert werden). tolower() verwandelt alle Buchstaben in Kleinbuchstaben. Also mußt du die Strings erst per tolower() ver"kleiner"n (eventuell brauchst du dafür auch eine locale-spezifische Variante, die die Umlaute mit behandelt und anschließend durch das collate<> jagen, um die Sortierung richtigzustellen.
-
aber wie sieht der quellcode dann aus ..ich weiss nicht wie ich das implementieren, definieren
soll .. muss ich das kaskadieren oder wie ?string sten;
sten="ich bin doch ein BAP..(BAP = Blödster Anzunehmenster Programmierer)";
-
Achtung - nicht getestet:
bool lexical_compare::operator()(string s1,string s2)//Übergabe per Wert ist beabsichtigt { //1) Umwandlung in Kleinbuchstaben: transform(s1.begin(),s1.end(),s1.begin(),bind2nd(std::tolower,std::locale()); transform(s2.begin(),s2.end(),s2.begin(),bind2nd(std::tolower,std::locale()); //Notiz an mich: Ich bin nicht ganz sicher, ob der bind2nd so klappt //2) Locale-abhängig vergleichen: const std::collate<char>& cmp=std::use_facet<std::collate<char> >(std::locale()); return cmp.compare(s1.data(),s1.data()+s1.size(),s2.data(),s2.data()+s2.size())<0; }
-
nur so nebenbei: locale besitzt selbst einen operator(), der genau dafür gedacht ist.
map<string,string,locale> localized_map(locale("de_DE.UTF-8"));falls das locale de_DE.UTF-8 vorhanden ist, kümmert es sich automatisch um die richtige lexikographische ordnung. (dafür reicht z.b. unter linux im CLI localedef -f UTF-8 -i de_DE de_DE.UTF-8)
alternativ kannst du dir dein eigenes facet ableiten:
class CollateIgnoreCase : public collate<char> { int do_compare (const char *A, const char* B, const char* X, const char* Y) const { /* leave it to you */ } std::string do_transform (const char* A, const char* B) { /* ... */ } ~CollateIgnoreCase () {} //dtor privat machen. s.u. }; void foo(); int main () { locale(locale(""), new CollateIgnoreCase); //locale kümmert sich um das delete //edit: das speichermanagement von locales und facets ist sowieso ein eigenes kapitel und imo nicht sehr intuitiv geregelt. wenn du das facet stand-alone verwenden willst, musst du dem basisklassenkonstruktor z.b. eine "1" übergeben. andernfalls schadet es sicherlich auch nicht, den destruktor privat (oder protected zu halten) foo(); } void foo () { map<string,string,locale> localized_map (locale("")); //hier musst du die "" angeben, weil locale keine funktion, sondern ein konstruktor ist und der ausdruck sonst eine funktionsdeklaration wäre. //... }
-
ein problem, dass bis jetzt übrigens mit jeder vorgeschlagenen lösung beachtenswert ist, die auf strings zuerst tolower anwedet, ist außerdem folgendes:
CStoll schrieb:
Achtung - nicht getestet:
bool lexical_compare::operator()(string s1,string s2)//Übergabe per Wert ist beabsichtigt { //1) Umwandlung in Kleinbuchstaben: transform(s1.begin(),s1.end(),s1.begin(),bind2nd(std::tolower,std::locale()); transform(s2.begin(),s2.end(),s2.begin(),bind2nd(std::tolower,std::locale()); //Notiz an mich: Ich bin nicht ganz sicher, ob der bind2nd so klappt //2) Locale-abhängig vergleichen: const std::collate<char>& cmp=std::use_facet<std::collate<char> >(std::locale()); return cmp.compare(s1.data(),s1.data()+s1.size(),s2.data(),s2.data()+s2.size())<0; }selbst, wenn das funktionieren würde, wäre es eine schlechte idee.
gegeben seien zwei strings, a und b, die sich jeweils nur in der groß/kleinschreibung unterscheiden. mit dieser implementation passiert es, dass lexical_compare::operator()(a,b) und lexical_compare::operator()(b, a) true liefern, was gleichbedeutend ist mit a == b. folglich wird ein element nicht einfügt, obwohl es das eigentlich sollte. vorstellbar z.b. bei "angeln - v, i, regulär" vs "Angeln - n, pl von Angel".das müsste man sowohl bei einer eigenen funktion/funktor korrigieren (a < A < b < B ...) als auch bei einer eigenen implementation von collate - wenn du das passende locale allerdings auf deinem pc hast (de_DE oder whatever), macht es das automatisch - das verhalten von solchen locales liegt aber außerhalb der definitionsmacht des C++ standards. eine lösung mit multimap wäre nicht zu empfehlen.
-
queer_boy schrieb:
nur so nebenbei: locale besitzt selbst einen operator(), der genau dafür gedacht ist.
map<string,string,std::locale> localized_map(std::locale("de_DE.UTF-8"));also ich hab das bei mir eingebaut und ich vermute das "de_DE.UTF-8" nicht bei mir existiert.. hab hier ein "deutsches XP" laufen..mit Visual 2005 express (german)als Entwicklungsumgebung. was funktioniert ist
map<string,string,locale> localized_map;ohne (std::locale("de_DE.UTF-8")); <<< wenn ich das einfüge gibs ein runtimeerror mit dem tollen hinweis: "This application has requested the Runtime to terminate it in an unusual way. please contact the application´s support team for more informations. "<< hihi da bin ja dann wohl ich gemeint..
falls ichs weglasse dieses (std::locale("de_DE.UTF-8") sortiert der wieder stupide erst grossbuchstaben dann klein.. nun da es wohl schwierig ist ein std: möglichkeit zu finden muss ich wohl oder übel selbst was bauen was die Umlaute richtig einsortiert. irgend ne billig switch case in der art
string result = str; for (size_t i=0; i < result.length(); i++) { result[i] = tolower(str[i]); switch(result[i]) { case 'ä': result[i] = 'a'; break;...
.. mal sehn ob ich das hinbekomm
-
unter windows heißt das locale vielleicht "German_Germany.1252" (brachte mir eine kurze suche mit google)
bleib mal bei map<string,string,locale> localized_map;
und probier mal am anfang deines program (in der main)locale::global(locale("")); //und lass dir den namen des locales ausgeben cout << "verwende nun " << locale().name() << endl;ich hab jetzt keinen standard bei mir, aber ich glaube nämlich, dass das globale locale standardmäßig auf das C (=en_US) locale gesetzt wird.