string einlesen + zeileninhalt trennen
-
hi leute,
die sufu des Forums hat mir leider in meinem fall nicht helfen können.
mein programm soll mit while(getline(datei,zeile)) mehrere zeilen einlesen, ok?
dabei soll aber gleich der zeileninhalt voneinander getrennt werden und in variablen abgelegt
1.blablabla 12.blablabla 7.blablabla usw.
zahl + trennzeichen + text
ich will also die zahlen vor dem trennzeichen extra haben, damit ich die zeilen sortieren kann
-
mit std::string.find und .substring kannst du sowas machen
-
die substring-before funktion sieht ganz brauchbar aus.
wie tu ich dort aber angeben, dass er aus der variable "zeile", wo die zeilen abgelegt werden, ausliest
substring-before(line,".") ??
und wie übergebe ich die zahlen vor dem trennzeichen an weitere variablen
kennt das programm dann auch die zuordnungen zwischen zahl und text, sodass man nach dem sortieren die richtigen texte bekommt
thx
-
das thema hatten wir doch erst
http://www.c-plusplus.net/forum/viewtopic-var-t-is-190098.html
in dem Beitrag von "Helfer" sollte eigentlich alles drin stehen.
-
gut, danke
der beitrag war mir nicht bekannt
-
pair<int, string> split(const string& zeile) { string::size_type position = zeile.find('.', 0); make_pair(zeile.substr(0, position), zeile.substr(position+1)); }
irgendwie nicht gnz richtig, wa?
mhh und wie soll man dann sortieren, wo sind die werte gespeichert
-
Fast richtig - jetzt mußt du nur noch den ersten Teil umwandeln in einen int-Wert (wie das geht, steht in der FAQ unter "Einmal String nach Zahl und zurück").
-
... "Einmal Zahl nach String und zurück" wa?
und was genau meinst du mit 1.teil?
-
End0X schrieb:
und was genau meinst du mit 1.teil?
zeile.substr(0,position)
ist immer noch ein String, der die "1" oder "12" in Textform enthält - den mußt du noch umwandeln in einen int-Wert, bevor du vernünftig damit rechnen kannst.
-
achso, ok
beim verwenden dieses befehls, bekomm ich jedoch nen fehler
int x = atoi(line.substr(0,position));
1error C2065: 'position': nichtdeklarierter Bezeichner
any ideas?
-
An welcher Stelle hast du denn das in die obige Funktion eingebaut? (btw, atoi() erwartet keinen std::string, sondern einen char* - den mußt du dir erstmal per c_str() besorgen:
int x = atoi(line.substr(0,position).c_str());
)
-
End0X schrieb:
mein programm soll mit while(getline(datei,zeile)) mehrere zeilen einlesen, ok?
Mmh! - nein nicht wirklich ok. Man sollte immer zunächst versuchen, das einzulesen, was man einlesen will. Und erst wenn das nicht mehr geht, kann man ganze Zeilen oder Dateien lesen, um sie dann mit irgendwelchen Parsern auseinander zu pflücken.
End0X schrieb:
zahl + trennzeichen + text
ich will also die zahlen vor dem trennzeichen extra haben, damit ich die zeilen sortieren kann
Also letztlich Zahl und Text - dann mache man sich eine Struktur
struct entry { int m_nummer; std::string m_restText; // -- Vergleichsmethode für's sortieren bool operator<( const entry& b ) const { return m_nummer < b.m_nummer; } };
Füge Funktionen zum Einlesen und vielleicht auch gleich welche zum Ausgeben hinzu
std::istream& trenner( std::istream& in ) { char t; if( in >> t && t != '.' ) in.setstate( std::ios_base::failbit ); return in; } // -- Entry lesen std::istream& operator>>( std::istream& in, entry& e ) { return std::getline( in >> e.m_nummer >> trenner, e.m_restText ); } // -- Entry schreiben std::ostream& operator<<( std::ostream& out, const entry& e ) { return out << e.m_nummer << '.' << e.m_restText << std::endl; }
.. und den Rest bekommt man dann schon fast geschenkt - jedenfalls ist es immer der gleiche Code
int main() { using namespace std; std::ifstream quelle( "input.txt" ); if( !quelle.is_open() ) { std::cerr << "Fehler beim Oeffnen der Datei" << std::endl; return -1; } std::vector< entry > log( (std::istream_iterator< entry >( quelle )), (std::istream_iterator< entry >()) ); std::sort( log.begin(), log.end() ); std::copy( log.begin(), log.end(), std::ostream_iterator< entry >( std::cout ) ); return 0; }
Als Include-Dateien sind dafür notwendig:
#include <iostream> #include <fstream> #include <string> #include <vector> #include <algorithm> // sort #include <iterator> // i/ostream_iterator<>
siehe auch hier.
Gruß
Werner
-
Werner Salomon schrieb:
...
std::istream& trenner( std::istream& in ) { char t; if( in >> t && t != '.' ) in.setstate( std::ios_base::failbit ); return in; }
...
Hmmm - ich wusste erst nicht, ob ich dem if-statement glauben kann, hab's dann aber begriffen: Wenn
!(in >> t)
, dann wird zwar dassetstate()
nicht mehr ausgeführt, aber das braucht's auch nicht, weil in dann sowieso schon den richtigen (="falschen" ) state hat.Schönes Idiom, werde ich mir merken (hofffentlich).
Gruß,
Simon2.
-
ich finds ja schon sehr beeindruckend, was Werner Salomon so hinbekommt.
finds nur (für meine verhältnisse) etwas kompliziert und unverständlichaber riesen lob und dank
-
End0X schrieb:
finds nur (für meine verhältnisse) etwas kompliziert und unverständlich
.. Ihr würdet in solchen Fällen mir - und damit letztlich auch Euch - helfen, wenn man mir genau sagen würde, was genau kompliziert aussieht und unverständlich ist. Klar ist das kein Anfänger Code, aber leider fällt es mir inzwischen schwer, zwischen Dingen die für Anfänger leicht zu verstehen sind und Dingen, die für mich leicht zu verstehen sind, zu unterscheiden. Deshalb bräuchte ich da etwas Support.
Also: was genau erscheint kompliziert und unverständlich?
Gruß
Werner
-
Simon2 schrieb:
Hmmm - ich wusste erst nicht, ob ich dem if-statement glauben kann, hab's dann aber begriffen: Wenn
!(in >> t)
, dann wird zwar dassetstate()
nicht mehr ausgeführt, aber das braucht's auch nicht, weil in dann sowieso schon den richtigen (="falschen" ) state hat.Also ich les' das so: erst wenn 'in >> t' gut gegangen ist - also true ist - erst dann ist das 't' gültig und darf auf Ungleichheit, oder was auch immer, geprüft werden.
Gruß
Werner
-
Werner Salomon
naja, eigentlich kann man ihn schon verstehen, wenn man nachguckt,welche befehle was auslösen.
aber will nicht meinen ganzen code umschreiben müssen
ich hätte jetzt zbsp strstrok benutzt (alles andere "splitten" ging irgendwie nicht) um den teil vor dem trennzeichen in eine und den danach in eine andere variable zu packen.
while(getline(infile,line)) vect.push_back(line); char *token; token = strtok(vect, ">"); while( token != NULL ) { cout << "%s\n" << token; token = strtok(NULL, ">"); }
so in der art. kommt aber dies
error C2664: 'strtok': Konvertierung des Parameters 1 von 'std::vector<_Ty>' in 'char *' nicht möglich
ich merke schon, dass man vieles beachten muss,beim coden. sonst entstehen zu viele konflikte. naja, amateurstyle halt :p
-
aber wie ich das danach sortieren soll,wüsste ich ehrlich gesagt auhc nicht
-
@End0X:
Überleg dir mal was du Schritt für Schritt machen willst. Was hat das für nen Sinn in ner while Schleife alles in nen vector zu packen und gleichzeitig zu teilen zu versuchen. Und bleib doch bei den Funktionen des std::strings und nimmt nicht wieder so strtok Zeugs.@Werner Salomons Code
Um sowas einfaches wie nen String bei nem Punkt zu teilen brauch ich doch nicht so n aufwendiges Zeug, dass man erst mal ne ganze Weile anschauen muss, um es zu verstehen. Findet ihr wirklich das sowas ne gute C++ Lösung ist?
-
blaurot schrieb:
...Findet ihr wirklich das sowas ne gute C++ Lösung ist?
Japp - weil es einer allgemeingültigen und -bekannten Struktur folgt, anstatt nur eine "Punktsuchfunktion" zu sein:
Den Datentyp entry kann man nun genauso über jeden Stream (cin/cout, i/ofstream, i/ostringstream oder jeden selbstgeschriebenen) einlesen und ausgeben wie wir das von bisherigen Typen (int, double, string, ...) kennen.Die Darstellung ist "dicht am Typen" und "dicht an der Ein/Ausgabe" implementiert: In "seinen" Streamoperatoren....
OK, trenner() hätte man auch direkt in operator>>() implementieren können, aber das wär's auch schon - und so ist er "allgemeingültig" (sprich: Kann auch für andere Datentypen genutzt werden).Ich finde es jedenfalls ein schönes Idiom ... in schönem C++.
Gruß,
Simon2.