Probleme bei Stringbearbeitung
-
Hallo zusammen,
ich brauche ein Funktion, die mir einen String formatiert. Der String ist in Blöcke von Zahlen unterteilt, die hier mit einem Doppelpunkt von einander getrennt sind.
Beispiel: 23:24:28:10:29:18:12:24:11:27:10:22:10:20:28
Nun muss ich diesen String von hinten lesen und jeweils die Zahlen der einzelnen Blöcke umdrehen. Hier sollte also rauskommen:
82:02:01:22....
Meine dazu geschriebene Methode kommt nur zu folgenden Fehlern, die anscheinend dann in einer Endlosschleife stecken bleiben:
*** Error in
./noob': free(): invalid next size (fast): 0x0000000001870770 *** \*\*\* Error in./noob': malloc(): memory corruption: 0x00000000018707a0 ***void myclass::format_output(std::string& raw_result) { std::stringstream output, tmp; bool delimiter_seen = true; std::cout << "\n\n" << raw_result << "\n\n"; for(std::string::reverse_iterator rit = raw_result.rbegin(); rit != raw_result.rend(); ++rit) { //rückwerts über String iterieren if(*rit != delimiter) { //Delimiter == ":" tmp << *rit; } else { if(delimiter_seen) { std::reverse(tmp.str().begin(), tmp.str().end()); output << tmp.str(); tmp.str(""); delimiter_seen = false; } else { delimiter_seen = true; } } } raw_result = output.str(); }Vielen Dank
LG, freakC++
-
Reverse den ganzen String einfach.
-
Ja, die Aufgabenstellung macht für mich nur wenig Sinn.
std::reverse sollte reichen, aber selbst das ist nicht wirklich sinnvoll.Wenn du jetzt noch an die (gerade umgedrehten) Daten kommen willst, um diese z.B. in einen vector zu schieben, dann kannst du folgendes machen (selbst das wäre wahrscheinlich noch eifnacher machbar):
std::vector<int> parse(std::string str) { std::reverse(str.begin(), str.end()); std::replace(str.begin(), str.end(), ':', ' '); std::vector<int> result; std::back_insert_iterator<std::vector<int>> back_it(result); std::stringstream ss(str); std::copy(std::istream_iterator<int>(ss), std::istream_iterator<int(), back_it); }ungetestet aus dem Kopf getippt...

-
3x komplett durchiterieren, 2x komplett kopieren. Bloß damit man die STL verwenden kann. Ein bisschen mehr Mühe bitte - die Standardbibliothek ist nicht dazu da, Probleme besonders umständlich, zu lösen sondern möglichst einfach.
Hier kämen wir mit einer einzigen Iteration und 0 Kopien aus.
-
Ja, aber dazu muss man mal kurz denken, und die Zeit hab ich grad nicht.

-
Sorry Leute! Ich habe Blödsinn geredet. Aus
23:24:28:10:29:18:12:24:11:27:10:22:10:20:28
soll
28:20:10:22:...
werden. Daher kann nicht einfach ein reverse machen. Deswegen ist mein Code etwas komplizierter. Sieht jemand das Problem?
Danke
-
Wieso musst du dann von hinten lesen? Pack das Ding in einen Stringstream, parse alle Zahlen (Doppelpunkte ignorieren) und kehr die Reihenfolge der Zahlen um. 1000x einfacher als alles was hier im Thread vorkam.
-
Ich glaube, ich verstehe dich nicht richtig. Ich mach mal vor, wie ich dich verstehe.
1.) 23:24:28:10:29:18:12:24:11:27:10:22:10:20:28
2.) 232428102918122411271022102028 //Doppelpunkte raus
3.) 82029122... //umdrehen.
Jetzt ist erstens verloren gegangen, wo die Doppelpunkte standen (die Zahlenblöcke können beliebig groß sein) und außerdem drehe ich so auch die Blöcke um.
Ziel ist es die Blockreihenfolge umzudrehen, nicht die Blöcke selbst.
Danke

-
Nein, du verstehst mich nicht richtig. Ich habe doch absichtlich **ignor(e)**ieren gesagt, nicht rausmachen.
Hier ist übrigens eine ganz nette Lösung für dein ursprüngliches Problem, beziehungsweise eine Lösung im Stil von Skym0sh0 aber mit
Skym0sh0 schrieb:
kurz denken
Ist auf den ersten Blick unnötig umständlich, aber so ein Iterator-basierter Streambuf kam mir sehr nützlich vor und ich konnte im Netz keinen fertigen finden. Daher veröffentliche ich ihn hier mal. ist natürlich noch leicht ausbaufähig, zum Beispiel könnte man den Iteratortyp erkennen und gegebenenfalls noch die ganzen Funktionen zum Zurücksetzen oder Positionieren anbieten, je nach dem, was der Iterator so kann. Für dieses einfachste Beispiel reicht ein Inputiterator:
#include <streambuf> #include <ios> template <typename Iterator> class iterator_streambuf : public std::streambuf { public: iterator_streambuf(Iterator begin, Iterator end): current(begin), end(end) { } protected: virtual int_type underflow() { if (current != end) return *current; else return traits_type::eof(); } virtual int_type uflow() { if (current != end) return *current++; else return traits_type::eof(); } private: iterator_streambuf( const iterator_streambuf& ); iterator_streambuf& operator=( const iterator_streambuf& ); Iterator current; Iterator end; }; #include <string> #include <iostream> #include <forward_list> int main() { { std::string foo = "!nebeirhcseg streawkceur remmi nedrew netfahcstoB ehcsinataS"; iterator_streambuf<decltype(foo.rbegin())> buf(foo.rbegin(), foo.rend()); std::istream in(&buf); for(std::string str; in >> str; std::cout << str << '\n'); } // edit: Oder etwas exotischer: { std::forward_list<int> foo = {52, 32, 56, 32, 49, 53, 32, 49, 54, 32, 50, 51, 32, 52, 50}; iterator_streambuf<decltype(foo.begin())> buf(foo.begin(), foo.end()); std::istream in(&buf); for(int i; in >> i; std::cout << i << ' '); std::cout << '\n'; } }
-
SeppJ schrieb:
Ist auf den ersten Blick unnötig umständlich, aber so ein Iterator-basierter Streambuf kam mir sehr nützlich vor und ich konnte im Netz keinen fertigen finden.
Wenn du schon im Himmel der Iteratoren bist, wieso möchtest du dann wieder zurück in die Höllen der Streams?
Rate mal, wie GCCs stdlibc++ den Input parst: Mit Stream-Iteratoren.
Das heisst in diesem Falle:
std::string s = "23:24:28:10:29:18:12:24:11:27:10:22:10:20:28:"; for (auto curr=s.rbegin(),last=curr;(last=curr++,curr=std::find(curr,s.rend(),':'))!=s.rend();) std::copy(curr.base(), last.base(), std::ostreambuf_iterator<char>(std::cout)); std::cout << '\n';Und du? Dein Ansatz kann genau Wörter bis zu nächsten Whitespace einlesen. Punkt. Nicht mehr. Was wenn an ":" getrennt werden soll (wie die Aufgabe *wirklich* lautete)? Dann halt von operator>> zu getline wechseln. Was wenn an ":" oder ";" getrennt werden soll? Ups. Das artet zu Locale-Rumgepfriemle aus. Will niemand.
-
Äh, natürlich
for (auto curr=s.rbegin(),last=curr;last=curr++,curr=std::find(curr,s.rend(),':'),last!=s.rend();)
-
eSsThehelL schrieb:
SeppJ schrieb:
Ist auf den ersten Blick unnötig umständlich, aber so ein Iterator-basierter Streambuf kam mir sehr nützlich vor und ich konnte im Netz keinen fertigen finden.
Wenn du schon im Himmel der Iteratoren bist, wieso möchtest du dann wieder zurück in die Höllen der Streams?
Rate mal, wie GCCs stdlibc++ den Input parst: Mit Stream-Iteratoren.
Ich glaube, du hast nicht kapiert, was mein Code macht. Iterator->Stream, nicht Stream->Iterator.
-
SeppJ schrieb:
eSsThehelL schrieb:
SeppJ schrieb:
Ist auf den ersten Blick unnötig umständlich, aber so ein Iterator-basierter Streambuf kam mir sehr nützlich vor und ich konnte im Netz keinen fertigen finden.
Wenn du schon im Himmel der Iteratoren bist, wieso möchtest du dann wieder zurück in die Höllen der Streams?
Rate mal, wie GCCs stdlibc++ den Input parst: Mit Stream-Iteratoren.
Ich glaube, du hast nicht kapiert, was mein Code macht. Iterator->Stream, nicht Stream->Iterator.
Ich glaube, du hast nicht kapiert:
Iterator:
Stream:
Folglich
Stream -> Iterator
Iterator -> Stream
-
Sicher.

edit: Mach doch mal das zweite Beispiel aus meinem Code mit deiner Methode nach.
-
Der Beweis meiner Behauptung sind die Umstände, die nötig sind, deinen Ansatz auf das richtige Problem anzupassen (an ":" splitten und den erhaltenen String zu reversen).
Und, dass dein Ansatz am verallgemeinerten Problem scheitert: "12:34;56" => "56;34:12" (also an ":" und ";" splitten und den Separator beibehalten).
Ich versuch mich solange an deinem exotischen Problem.
-
Häh? Wovon redest du überhaupt? Dem Iterator->Stream oder der schnellen Lösung für das vereinfachte Problem?
Egal, beide haben überhaupt kein Problem mit irgendwelchen Separatoren. Ich bin immer mehr überzeugt, dass du gar nicht kapierst, was der Code macht.
-
Dein "exotisches" Problem:
std::forward_list<char> s = {53, 32, 56, 32, 49, 53, 32, 49, 54, 32, 50, 51, 32, 52, 50}; bool last_was_digit = true; for (char c : s) if (!std::isdigit(c)) last_was_digit = false; else last_was_digit = std::cout << (last_was_digit?"":" ") << c;Löse du mal das Problem von freakC++ mit deiner Streamlösung: "12:34:56" soll werden zu "56:34:12". Und das möglichst ohne (a) Integer-Overflows (b) alles zu kopieren bei der Eingabe "allesohnedoppelpunkte".
-
??? Aufmerksam lesen: Meine Streamlösung ist für den Fall, dass 12:34:56 zu 65, 43, 21 werden soll. So wie vom TE ursprünglich verlangt und als Demonstration für Skym0sh0, wie es ohne drei Umwege und trotzdem universell gehen könnte. Damit ist das eine ganz wunderbare Lösung, die kaum einen Prozessortakt zu viel verschwendet, dabei aber universell auf viele Probleme angewandt werden kann.
Zu deiner Lösung meines exotischen Problems: Ähh, du hast es nicht gelöst. Es geht nicht darum, die Zeichen auszugeben. Ich will die Zahlen haben! Wir wollen damit rechnen.
Wenn du nun beginnst, num_get nachzuprogrammieren: Holzweg. Dann fang ich an, Fließkommazahlen hexadezimal in Scientificschreibweise mit Vorzeichen in die Liste zu packen und es soll immer noch funktionieren. Bitte eine universelle Lösung, die meiner ebenbürtig ist.
-
Ziel ist es die Blockreihenfolge umzudrehen, nicht die Blöcke selbst.
Und wenn du nun 'Block' durch 'Woerter' ersetzt, erkennst du, dass das Internet viele bekannte Loesungen in vielen bekannten und unbekannten Sprachen bereithaelt. Denken muss man wirklich nicht. Oder der MAtrixstil: Nicht denken, wissen!
Ach, ich bin da eher faul: http://www.geeksforgeeks.org/reverse-words-in-a-given-string/
Einfach ' ' durch ':' ersetzen, http://ideone.com/Xc1Sz5 . Mann muss zwei Mal drueberiterieren, ist aber inplace. Trivial parallelisierbar. Um Sonderfaelle zu beachten, brauche ich eine bessere Problembeschreibung.
-
Genau das wollte ich machen. Mein Algorithmus ist dem doch dann gar nicht so fern....
Danke!
LG, freakC++