string nach map inhalten durchsuchen und ersetzen
-
hai...
ich habe mal wieder ein suche/ersetze problem und komme einfach nicht weiter.
ich haben eine map:map<string, int> deineMap; deineMap["Strasse"] = 1; deineMap["trasse"] = 2; deineMap["rasse"] = 3; deineMap["asse"] = 4; deineMap["sse"] = 5; deineMap["se"] = 6; deineMap["Haus"] = 7; deineMap["aus"] = 8; deineMap["us"] = 9;und einen string:
string text; text = "Wir stellen Strassenschilder und Hausnummern fuer den privaten Bereich her.";nun möchte ich den string nach den inhalten der map durchsuchen. wenn sich im string der selbe inhalt wie in einem teil der map befindet, möchte ich diesen im string durch einen code (eine zeichenkette = "\e" und die stelle in der map z.b. 2) ersetzen. quasi um den string zu verkürzen. der string soll also in diesem beispiel am ende so aussehen:
text = "Wir stellen \e1nschilder und \e7nummern fuer den privaten Bereich her."dazu wollte ich folgendes script benutzen:
#include <map> #include <string> #include <iostream> using namespace std; int main( ) { map<string, int> deineMap; deineMap["Strasse"] = 1; deineMap["trasse"] = 2; deineMap["rasse"] = 3; deineMap["asse"] = 4; deineMap["sse"] = 5; deineMap["se"] = 6; deineMap["Haus"] = 7; deineMap["aus"] = 8; deineMap["us"] = 9; string text; text = "Wir stellen Strassenschilder und Hausnummern fuer den privaten Bereich her."; for (int i=0; i<deineMap.size(); i++){ text.replace( text.find( deineMap[i]), strlen(deineMap[i]), "\e"i); } cout << text << endl; system("PAUSE"); }leider haut der blödsinn überhaupt nicht hin. kann mir jemand helfen?
-
steven23 schrieb:
...der blödsinn ...
Daran wird's liegen.

Ganz auf die Schnelle:- Wenn Du einen Container elementweise durchgehen willst, ist ein iterator das Mittel der Wahl.
- "\e"i gibt's nicht in C++; mag in Shellskripten gut funktionieren - hier nicht. => schau mal nach "Zahlen in Strings umwandeln".
- Nicht strlen() auf strings anwenden.
- bei "map<string, int> deineMap" erwartet deineMap[....] einen String als Parameter - und liefert ein int zurück (was du nicht als string::find()-Parameter nehmen kannst).
- Brauchst Du nicht eine "map<int, string>" ? Oder reicht nicht sogar ein vector<string> (sogar besser ?) ... erst Recht, wenn Du die ints "lückenlos belegst"....
- Brauchst Du überhaupt die Flexibilität eines Containers ? substr() könnte Dir evtl einiges ersparen...
ich probier mal was aus ....
EDIT: (Das funktioniert so)
vector<string> deinVector; deinVector.push_back("Strasse"); deinVector.push_back("trasse"); deinVector.push_back("rasse"); deinVector.push_back("asse"); deinVector.push_back("sse"); deinVector.push_back("se"); deinVector.push_back("Haus"); deinVector.push_back("aus"); deinVector.push_back("us"); const vector<string>::const_iterator vend = deinVector.end(); int i =0; size_t pos; for(vector<string>::const_iterator p = deinVector.begin(); vend != p; ++p) { ostringstream o; o << "\\e" << ++i; if(string::npos != (pos = s.find(*p))) s.replace(pos, (*p).length(), o.str()); }Gruß,
Simon2.
-
#include <vector> #include <string> #include <sstream> #include <iostream> using namespace std; int main( ) { vector<string> deinVec; deinVec.push_back( "Strasse" ); deinVec.push_back( "trasse" ); deinVec.push_back( "rasse" ); deinVec.push_back( "asse" ); deinVec.push_back( "sse" ); deinVec.push_back( "se" ); deinVec.push_back( "Haus" ); deinVec.push_back( "aus" ); deinVec.push_back( "us" ); string text, rep = "\\e", item; size_t pos; text = "Wir stellen Strassenschilder und Hausnummern fuer den privaten Bereich her."; stringstream ss; for( unsigned int i = 0; i < deinVec.size(); ++i ) { ss.str( "" ); ss << rep << i; item = deinVec[i]; pos = text.find( item ); if( pos != string::npos ) text.replace( pos, item.length(), ss.str() ); } cout << text.c_str() << endl; cin.get(); return 0; }
-
// Zeile 31 pos = 0; while( (pos = text.find( item, pos + item.length() )) != string::npos ) text.replace( pos, item.length(), ss.str() );
-
Hi,
ich habe nochmal ein wenig rumgebastelt und 3 "Lösungen" ausprobiert:
void f_strVector1(string & s) { // Vector-Variante 1 (vectorelemente beinhalten auch substr-Varianten) vector<string> deinVector; deinVector.push_back("Strasse"); deinVector.push_back("trasse"); deinVector.push_back("rasse"); deinVector.push_back("asse"); deinVector.push_back("sse"); deinVector.push_back("se"); deinVector.push_back("Haus"); deinVector.push_back("aus"); deinVector.push_back("us"); const vector<string>::const_iterator end = deinVector.end(); unsigned int i=0; size_t pos; for(vector<string>::const_iterator p = deinVector.begin(); end != p; ++p) { ostringstream o; o << "\\e" << ++i; if(string::npos != (pos = s.find(*p))) s.replace(pos, (*p).length(), o.str()); } } void f_strMap(string & s) { // Map-Variante map<int, string> deineMap; deineMap[1] = "Strasse"; deineMap[2] = "trasse"; deineMap[3] = "rasse"; deineMap[4] = "asse"; deineMap[5] = "sse"; deineMap[6] = "se"; deineMap[7] = "Haus"; deineMap[8] = "aus"; deineMap[9] = "us"; for (size_t i=1; i<deineMap.size(); i++){ ostringstream o; size_t pos; o << "\\e" << i; if(string::npos != (pos = s.find(deineMap[i]))) s.replace(pos, deineMap[i].length(), o.str()); } } void f_strVector2(string & s) { // Vector-Variante 2 (vectorelemente beinhalten nur die "Basisstrings") vector<string> deinVector; deinVector.push_back("Strasse"); deinVector.push_back("Haus"); vector<string>::const_iterator const end = deinVector.end(); size_t i=0, pos; for(vector<string>::const_iterator p = deinVector.begin(); end != p; ++p) { // Pro element noch die möglichen Substrings durchgehen string substring = *p; while(substring.length() > 1) { ostringstream o; o << "\\e" << ++i; // Wichtig: Der "zählt durch" if(string::npos != (pos = s.find(substring))) s.replace(pos, substring.length(), o.str()); substring = substring.substr(1); } } }Was davon am besten für Dich passt, musst Du selbst entscheiden.
- Die Vector2-Variante ist die "schmalste" und ideal dafür, wenn es genau darum geht: Nach Suchworten und deren "Endteilen" zu suchen.
- Die Vector1-Variante gibt zusätzlich die Möglichkeit, voneinander unabhängige Suchbegriffe zu verwenden (besonders, wenn nicht immer alle "Endteile" oder wenn spezielle Substring-Formen gebraucht werden).
- Die Map-Variante habe ich nur in Anlehnung an Deinen Code implementiert (bietet IMO keinen zusätzlichen Nutzen gegenüber der Vector1-Variante), aber:
- wenn man die Suche noch ein wenig "umstrickt" (map per iterator durchsuchen), kann man die "Indizes und Werte" noch viel flexibler handhaben (z.B. auch "mit Lücken hochzählen" .... und schließlich:
- Die letzte Variante wäre letztlich zu einem generellen "Suchen&Ersetzen" umstrickbar, indem man eine "map<string, string>" anlegt, in der (am Besten im ersten Parameter) "Suchbegriff" und "Ersetzbegriff" verknüpft sind. Diese Variante bleibt dem geneigten Leser zur Übung überlassen ....

Gruß,
Simon2.
-
Du hast damit (wenn ich das richtig sehe) immernoch dasselbe Problem wie Airdamn, siehe meinen letzten Beitrag für den "Patch".
-
.filmor schrieb:
Du hast damit (wenn ich das richtig sehe) immernoch dasselbe Problem wie Airdamn, siehe meinen letzten Beitrag für den "Patch".
Nö. :p
In seinem Beispieltext hat steven auch jeweils nur das erste Auftreten des substrings ersetzt ....
vielleicht war das nicht gewollt, vielleicht auch doch.
Falls nicht,
- war nicht sein Hauptproblem,
- hätte er bestimmt auch noch gefunden/gelöst
- wäre ihm per "Klartexthinweis" vielleicht etwas schneller aufgefallen.

Gruß,
Simon2.
-
Simon2 schrieb:
.filmor schrieb:
Du hast damit (wenn ich das richtig sehe) immernoch dasselbe Problem wie Airdamn, siehe meinen letzten Beitrag für den "Patch".
Nö. :p
Aber sowas von

Simon2 schrieb:
In seinem Beispieltext hat steven auch jeweils nur das erste Auftreten des substrings ersetzt ....
Weil es nur ein Auftreten gab. Die Problembeschreibung war:
steven23 schrieb:
nun möchte ich den string nach den inhalten der map durchsuchen. wenn sich im string der selbe inhalt wie in einem teil der map befindet, möchte ich diesen im string durch einen code (eine zeichenkette = "\e" und die stelle in der map z.b. 2) ersetzen. quasi um den string zu verkürzen.
Da steht nichts vom ersten Vorkommen, also muss jedes Vorkommen gemeint sein (ist aber an der Stelle ungenau).
Simon2 schrieb:
- war nicht sein Hauptproblem,
Stimmt.
Simon2 schrieb:
- hätte er bestimmt auch noch gefunden/gelöst
Stimmt.
Simon2 schrieb:
- wäre ihm per "Klartexthinweis" vielleicht etwas schneller aufgefallen.
Stimmt auch. Aber man kann doch nicht einfach falschen Code hier stehen lassen und sogar noch mit dem Fehler weiterbauen ;).
Schau dir mal den Thread zu den "Forwärtsdeklarationen" an
-
Hi,
eigentlich sprach ich nicht von seinem Programmausgabe, sondern von
a) seinem Quellcodesteven23 schrieb:
...
for (int i=0; i<deineMap.size(); i++){ text.replace( text.find( deineMap[i]), strlen(deineMap[i]), "\e"i); }...
Hier macht er genau das und
b) seiner Aufgabenbeschreibung:steven23 schrieb:
...nun möchte ich den string nach den inhalten der map durchsuchen. wenn sich im string der selbe inhalt wie in einem teil der map befindet, möchte ich diesen im string durch einen code (eine zeichenkette = "\e" und die stelle in der map z.b. 2) ersetzen....
Da steht nix von "jedes Auftreten"; semantisch nutzt er sogar den Singular.

Gruß,
Simon2.
P.S.: Du hast natürlich Recht, dass ich mir über dieses Verhalten gar keine Gedanken gemacht habe, weil es mir mehr um die aufgabenadäquate Verwendung von Map/Vector ging ...

-
beim umgedrehten versuch scheitert es mal wieder und ich weiß nicht weiter.
ich habe einen string = "Haupt\e2 und Verkehrs\e3"
der zu "Hauptstrasse und Verkehrschilder" werden soll.
dazu hole ich mir den code aus einer map. leider klappt dies nicht... hat jemand ein tipp?#include <iostream> #include <string> #include <map> int main() { std::string coded = "Haupt\e2 und Verkehrs\e3"; std::map<unsigned long ,std::string> mtest; mtest.insert(std::pair<unsigned long,std::string>(0x30,"tunnel")); mtest.insert(std::pair<unsigned long,std::string>(0x31,"weg")); mtest.insert(std::pair<unsigned long,std::string>(0x32,"strasse")); mtest.insert(std::pair<unsigned long,std::string>(0x33,"schilder")); int stroffset = coded.find('\e'); while(stroffset != coded.npos) { int zeile = stroffset+2; coded.replace(coded.find('\e'), 2, mtest[zeile].second); stroffset = coded.find('\e'); } cout<< "Decodierter Name: "<< coded << endl; cin.get(); }
-
kann mir denn keiner helfen?
-
1. Benutz
"\\e"statt
'\e', du musst den Backslash escapen.
2. Der Buchstabe an der Position ist nicht gleich seinem Index!! Du musst den Indexoperator benutzen;
int zeile = coded[stroffset + 2]3. "\\eN" ist 3 Zeichen lang!
coded.replace(coded.find("\\e"), 3, mtest[zeile]);4. (oben schon korrigiert) mtest[zeile] liefert einen std::string, kein pair
5. Du musst beim zweiten Mal (also in der while-Schleife) der find-Methode die alte Position+3 übergeben:
stroffset = coded.find('\e', stroffset + 3);6. Es heißt std::cout und std::cin.
Hier nochmal der komplette (funktionierende) Code:
#include <iostream> #include <string> #include <map> int main() { std::string coded = "Haupt\\e2 und Verkehrs\\e3"; std::map<unsigned long ,std::string> mtest; mtest.insert(std::pair<unsigned long,std::string>(0x30,"tunnel")); mtest.insert(std::pair<unsigned long,std::string>(0x31,"weg")); mtest.insert(std::pair<unsigned long,std::string>(0x32,"strasse")); mtest.insert(std::pair<unsigned long,std::string>(0x33,"schilder")); int stroffset = coded.find("\\e"); while(stroffset != coded.npos) { int zeile = static_cast<int> (coded[stroffset + 2]); coded.replace(coded.find("\\e"), 3, mtest[zeile]); stroffset = coded.find("\\e", stroffset + 3); } std::cout << "Decodierter Name: "<< coded << std::endl; std::cin.get(); }So, und das nächste Mal solltest du vielleicht, anstatt schon nach einem Tag zu pushen 1. die Compilerfehler und Warnungen beachten und 2. nach deren Ausmerzung den Code einigemale ausführen. Ersteres hätte die Probleme 1, 4 und 6 gelöst, letzteres den Rest.
-
danke
-
Hi steven,
ein Tipp von mir noch: Wenn Du "etwas abstrakter arbeitest", wirst Du Dir Fehler wieder diese:
.filmor schrieb:
...
3. "\\eN" ist 3 Zeichen lang!coded.replace(coded.find("\\e"), 3, mtest[zeile]);...
stroffset = coded.find('\e', stroffset + 3);...
öfter sparen.
Also: Nicht überall '/e' oder "/e", sondernstd::string const Marker = "//e"; ... coded.replace(coded.find(Marker), Marker.length(), mtest[zeile]);und so weiter.
Das verhindert falsche Längen und (oftmals) auch Typen Marker ist eben ein std::string und kein (const) char*) ...Gruß,
Simon2.