Datei Zeichenweise importieren
-
Hallo erstmal,
ich habe nur rudimentäre Erfahrung mit C++ und versuche gerade etwas ähnliches zu machen, was ich schon einmal gemacht habe. Und zwar will ich eine Textdatei einlesen und zwar am Besten Zeichenweise. Denn wenn eine bestimmte Zeichenfolge erscheint, will ich das was danach kommt in eine Variable schreiben solange bis wieder ein bestimmtes Zeichen kommt. Also wenn das hier dasteht:
<IP1>123.456.78</IP1>
will ich das einlesen bis das erste ">" kommt, den Rest in eine Variable schreiben bis "</" kommt. Wie ich die Datei einlese weiß ich schon:
ifstream datei ("test.txt"); string zeile; while (getline (datei, zeile)) { cout << zeile << endl; }Ich weiß gerade nur nicht, wie ich den string "zeile" zeichenweise durchsuche - auch nach einem ausführlichen Googeln hab ich den entsprechenden Befehl nicht gefunden. Kann mir da jemand vielleicht einen kleinen Tipp geben oder mich zumindest in die richtige Richtung (Tutorial?) stupsen?
Danke schonmal!
Schnitzel
-
Hallo,
du bist im falschen Subforum - hier ist C++/CLI (vllt. verschiebt ein Mod deinen Beitrag?).
Du kannst einen std::string ganz normal über Indizes ansprechen, d.h.
for(int i=0; i<zeile.length(); i++) { char c = zeile[i]; }Die fortgeschrittenere Variante wäre die Verwendung von Iteratoren.
Um nach einer Zeichenfolge zu suchen, kannst du auch die find-Funktion verwenden:
size_t pos1 = zeile.find("<IP1>"); size_t pos2 = zeile.find("</IP1>"); string ip = zeile.substr(pos1+5, pos2-pos1-5);Und die letzte Codezeile extrahiert die IP anhand der zwei gefundenen Positionen (der zweite Parameter ist die Länge.
Als gute Hilfe für die C++ Library kann ich dir http://www.cplusplus.com empfehlen. Für die String-Methoden: http://www.cplusplus.com/reference/string/
-
Ach Mist, sorry wegen dem falschen Forum.
Aber vielen Dank für deine Antwort, die hilft mir schon mal extrem weiter! Mit den Iteratoren ist das natürlich viel eleganter. Jetzt habe ich da nur noch ein kleines Problem: wie sage ich ihm, dass er nichts in den String IP schreiben soll, wenn er <IP1> nicht in der Zeile findet? Ich habs mit einer einfachen if-Funktion probiert
if (pos1!=Null)
aber das funktioniert so nicht. Wie frage ich danach, ob er "<IP1> gefunden hat?
-
Wenn der Teil nicht gefunden wurde, liefert find die Konstante string::npos - damit kannst du dann vergleichen:
size_t pos1 = zeile.find("<IP1>"); size_t pos2 = zeile.find("</IP1>"); if(pos1!=string::npos) { string ip = zeile.substr(pos1+5, pos2-pos1-5); ... } else // keine IP1 in der aktuellen Zeile
-
Vielen Dank für die Antworten. Damit hab ich es jetzt mitbekommen.
Aber jetzt hätte ich eine andere Frage: um die Daten zu speichern möchte ich eine Klasse deklarieren und das eingelesene dann in die Variabeln der Klasse schreibe. Das ist auch kein Problem. Nur würde ich außerdem gerne am Anfang der XML-Datei nachfragen, um wieviele Datensätze es geht, damit ich auch weiß wieviele Klassen ich brauche. Und dann würde ich je nach Eingabe dann eben auch eine bestimtme Anzahl von Instanzen der Klasse erstellen.
Also praktisch so:
Er liest ein es gibt 5 Datensätze.
Dann würde ich es gerne irgendwie so machen:
for(i=1; i<=datensaetze; i++)
{Class class"i" (also hier mit irgendeinem Befehl die Variable von oben in den Namen der Instanz schreiben);}So geht das natürlich leider nicht - aber ist es sonst irgendwie möglich (ohne dass es jetzt extrem kompliziert wird), oder sollte ich einfach von Anfang an zig Instanzen erstellen, und wenns doch zu wenig sind am Anfang eine Fehlermeldung ausgeben?
-
Dieser Thread wurde von Moderator/in Jochen Kalmbach aus dem Forum C++/CLI mit .NET in das Forum C++ (auch C++0x) verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Eine Möglichkeit wäre es natürlich, irgendwo am Anang der eingelesenen Datei die Anzahl zu schreiben. Aber einfacher geht es, wenn du eine Datenstruktur verwendest, die mitwachsen kann:
vector<Satz> inhalt; Satz tmp; while(xmlfile.readsatz(tmp)) inhalt.push_back(tmp);(nach dem Einlesen kannst du per inhalt.size() erfahren, wieviele Datensätze du hast)
-
Am Anfang der XML-Datei werde ich eh die Anzahl schreiben müssen... wie würde es denn damit funktionieren? Mit Vektoren kenne ich mich so gar nicht aus, deshalb würde ich wenns geht es lieber anders lösen.
-
Also rein von der Logik her - wieso brauchst du mehrere Klassen, um die IPs dann in UNTERSCHIEDLICHEN Klassen zu bearbeiten? Macht es nicht viel mehr Sinn, EINE Klasse anzulegen und dort eben ein private vector/array, in dem die Daten gespeichert werden?
Hier mal ein ungetestetes Bsp:#include <iostream> #include <string> #include <vector> using namespace std; class Datensatz { private: vector<string> m_IPs; public: Speichern( string daten ) { m_IPs.push_back( daten ); } Anzeigen( int nummer ); { cout << "Datensatz Nummer " << nummer << ": " << m_IPs.at( nummer ) << endl; } Editieren( int nummer, string daten ) { m_IPs.at( nummer ) = daten; } };Weiß nicht, wie ich das erklären soll - denke durch die Bezeichnung und da es alles Einzeiler sind, ist es fast schon selbsterklärend

So würde das Speichern ablaufen (Codefetzen zusammen gewürfelt):
int main( int argc, char **argv ) { string Datei = "Test.xml"; Datensatz datensatz; /* Die Klasse */ ifstream fromFile( Datei.c_str( ) ); if( fromFile.fail( ) ) { cout >> "Fehler beim Öffnen der Datei: " << Datei << endl; return 0; } while( !fromFile.eof( ) ) /* Finde das persönlich besser als while( getinline( fromFile, Line ) ) { ... } */ { string Line; getinline( fromFile, Line ); // if( Line.empty( ) || Line[0] == '#' ) /* Oder ein anderes Zeichen, um in der Datei Kommentare anzulegen */ // continue; /* Nicht notwendig in einer xml-Datei (?) */ size_t beg = Line.find( "<IP1>" ); size_t end = Line.find( "</IP1>" ); if( beg == string :: npos ) /* Keine IP in dieser Zeile */ continue; /* => Neue Zeile wird durchsucht */ string Ip = zeile.substr( beg + 5, end - beg - 5 ); /* Ip wird herausgefiltert */ datensatz.Speichern( Ip ); /* Ip wird in der Klasse im vector m_IPs gespeichert */ } return 0; }