Probleme bei Stringbearbeitung
-
Ä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++
-
verallgemeinerten Problem
Soll ich mal anfangen zu verallgemeinern?
1.) Variabler Separator
2.) Separator variabler Laenge
3.) Separator escapen um als Teilwort betrachtet zu werden.
4.) Escapezeichen escapen
5.) Keine Strings sondern Streams mit verschiedenen Fehlerzustaenden
6.) Keine Strings sonder Bitstreams deren Wortgroesse kein Vielfaches von 8 Bit sind
7.) Muahahahaha
8.) Werner darf nicht mitmachen
9.) Mehr Muahahahaha ...
-
Dank knivils Link habe ich meine Methode nun wie folgt umgebaut. So funktioniert der Minialgorithmus und ich meiner Ansicht auch recht performant.
Hat jemand was dagegen?

void myclass::format_output(std::string& raw_result) { std::string::iterator num_begin = raw_result.begin(); for(std::string::iterator it = raw_result.begin(); it != raw_result.end(); ++it) { if(*it == delimiter){ std::reverse(num_begin, it); num_begin = it+1; } } std::reverse(raw_result.begin(), raw_result.end()); raw_result.erase(0,1); }Viele Grüße
freakC++
-
Hat jemand was dagegen?
Warum sollte es eine Methode und nicht eher eine freie Funktion sein?
-
weil ich die Funktion nur in meiner Klasse brauche. Das würde dem Prinzip der Kapselung wiedersprechen.
Später brauche ich die Klasse nur als Hilfsmittel. Diese Formatierungsfunktion ist privat und muss nicht nach außen sichtbar sein.
-
Es gibt viel bessere Alternativen. Datenkapselung ist es auch nicht, da diese Methode keine Daten der Klasse benutzt. Es ist eine freie Funktion, guter C++ Stil respektiert das, indem sie als freie Funktion implementiert wird.
-
SeppJ schrieb:
??? 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
Ja, ursprünglich.
freakC++ schrieb:
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?
Sollte doch nur eine kleine Änderung in deinem Code sein sein, nicht?
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.

Ich habe mal deine Lösung mitstd::string foo = "!nebeirhcseg streawkceur remmi nedrew netfahcstoB ehcsinataS"; for (int i=0; i<20; i++) foo = foo + foo;getestet und ich erhalte:
reverse string + streambuf: 3.30s user 0.16s system 99% cpu 3.467 total seppjs reversed streambuf : 2.93s user 0.10s system 99% cpu 3.034 total iterator + for-loo p : 0.78s user 0.10s system 99% cpu 0.883 totalOooh, wie unerwartet. istream hält einen eigenen buffer, ostream hält einen buffer und formatierter Input ist teuer.
std::ostreambuf_iterator<char> out(std::cout); auto it=foo.rbegin(), end=foo.rend(); while (it != end) { while (std::isspace(*it) && it != end) ++it; while (!std::isspace(*it) && it != end) *out++ = *it++; *out++ = ' '; }Meine Aussage: IOstream-Parsen ist sehr langsam und für Nicht-Whitespace-getrennten-Standarddatentypen-Input enorm umständlich. (Bei langsamen Festplatten fällt das Parsen vielleicht weniger ins Gewicht, aber wenn der Input schon im RAM ist, ist stringstream der Tod)
Für Speed soll man auf Iteratoren wechseln (istreambuf_iterator im Fall von externen Streams, sonst halt was gegeben ist). Ist oft auch kürzer und einleuchtender. Wenn einem Whitespaces egal sind, ist der Stream nur hinderlich.
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.
Das ist deine Interpretation fürs Problem. Klar ist eine Streamlösung einfacher, wenn wir Parsen wollen. Das war aber nie gefragt.
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.
Nimmstu std::stoi. Das Design der Iostreams ist so kaputt, dass ich num_get nur mit istreambuf_iterator<char|wchar_t> verwenden kann (d.h. ich brauche deinen Iter2Streambuf aufgrund von Iostream-Limitations).
Ich wiederhole: Wie würdest du die eigentliche (im Gegensatz zur ursprünglichen) Aufgabe von freakC++ lösen?
-
knivil schrieb:
Datenkapselung ist es auch nicht, da diese Methode keine Daten der Klasse benutzt.
Stimmt nicht. "delimiter" ist ein Klassenattribut. In jeder Software Engineering Vorlesung lernst Du, dass frei in der Welt herumfliegende Funktionen nicht gut sind. Zwar wird nur auf "delimiter zugegriffen, was ehrlich gesagt ein char ist, aber die Funktion gehört logisch zur Aufgabe der Klasse. Sie ist Teil einer Verantwortlichkeit und gehört für mich daher in die Klasse. Außerdem habe ich dann den Namen der Funktion nicht vergeben.
eSsThehelL schrieb:
Für Speed soll man auf Iteratoren wechseln (istreambuf_iterator im Fall von externen Streams, sonst halt was gegeben ist). Ist oft auch kürzer und einleuchtender. Wenn einem Whitespaces egal sind, ist der Stream nur hinderlich.
Ich hoffe, dass duch dich nur auf das Parsen beziehst. Ich baue gerade einer BigInteger Klasse, die ihre Ergebniss zum Schluss in einem String zurückgibt. Alle Zwischenergebnisse werden nach und nach in einen stringstream geschoben. So geht es am einfachsten.
Oder ist das zu langsam und es gibt noch bessere Methoden, die für mich bislang unbekannt waren?
Danke
-
freakC++ schrieb:
knivil schrieb:
Datenkapselung ist es auch nicht, da diese Methode keine Daten der Klasse benutzt.
Stimmt nicht. "delimiter" ist ein Klassenattribut. In jeder Software Engineering Vorlesung lernst Du, dass frei in der Welt herumfliegende Funktionen nicht gut sind. Zwar wird nur auf "delimiter zugegriffen, was ehrlich gesagt ein char ist, aber die Funktion gehört logisch zur Aufgabe der Klasse. Sie ist Teil einer Verantwortlichkeit und gehört für mich daher in die Klasse. Außerdem habe ich dann den Namen der Funktion nicht vergeben.
Was spricht gegen eine freie Funktion:
void format_output(std::string &raw_result, char delimiter);?
Und schon hast du wesentlich mehr Flexibilität.
-
Nichts, aber ich brauche sie nie wieder. Ich brauche sie in einer Klasse einmal. Diese Klasse soll dann später in andere mit eingebunden werden. Da ist es mir irgendwie lieber, wenn die Methoden zu irgendjemandem gehören.
Vielleicht habe ich aber auch nur zu viel Java programmiert und zu gut in Software Engineering aufgepasst^^
lg, freakC++
-
freakC++ schrieb:
In jeder Software Engineering Vorlesung lernst Du, dass frei in der Welt herumfliegende Funktionen nicht gut sind.
Ne. Nur in denen, wo Propaganda für Java gemacht wird. Aber aus Interesse, was war die Begründung? Gabs überhaupt eine oder sind Behauptungen dort grundsätzlich richtig?
freakC++ schrieb:
Zwar wird nur auf "delimiter zugegriffen, was ehrlich gesagt ein char ist, aber die Funktion gehört logisch zur Aufgabe der Klasse.
Impliziert noch keine Member-Funktion.
freakC++ schrieb:
Außerdem habe ich dann den Namen der Funktion nicht vergeben.
Der Name ist nicht vergeben. Überladung, Namensräume, cpp-lokale Deklarationen...
Lies vielleicht bei Gelegenheit diesen Artikel. Freie Funktionen sind ein wichtiges C++-Sprachmittel.