Wie kann ich variable Zahlen aus einer Zeile, die in einem Buffer ist, extrahieren?
-
Hallo erstam und herzlichen Dank für die Antwort.
Sorry das ich diese Zusatzinformationen vergessen habe anzugeben.
Also:- Es handelt sich bei dieser Zeile um eine Speicherauslastung und Bereinigung meines Servers die in eine Datei geschrieben wird
- Der erste Zahlenwert ist der Zeitstempel, ich gehe davon aus alles vor dem Punkt sind Sekunden, hinter dem Punkt Millisec.
- Die anderen Zahlen räpresentieren die Speicher(Haupt-Sp./Statischer-Sp.)jeweils "Wieviel gerade belegt ist" dann "die Bereinigungsmenge" und "der Max-Speicher"
Ich hoffe das Hilft ein wenig um die Zeile nachvolziehen zu können.
ICh versuche der weil mal einen Datentyp "Eintrag" zu erstellen.
-
Hallo Fill,
wie Kellerautomat schon sagte, wäre Schritt 1, eine Struktur
Eintrag(oder so) zu bauen, die sozusagen der Datensatz ist, der den Inhalt einer Zeile beschreibt. Für diesestruct Eintragbaue man sich die sogenannten Streaming-Operatoren und dort findet dann das eigentliche Lesen und Schreiben genau eines Eintrags statt.
In Deinem Fall ist es sicher angebracht, sich auf markante Zeichen in dem Text zu konzentrieren, die möglichst nur vor der jeweils nächsten Zahl auftauchen. Solche Stellen kann man mit der Methode ignore gezielt 'anspringen'.
Also bei "35.121**:** [Full GC (System) [PSYoungGen**:** 51172K->0K**(**764608K)] ... " ist das der ':' und die '('. Bei der zweiten Zahl (hier 51172K) muss man schon aufpassen, da der ':' bis dahin zweimal auftaucht.Ich habe das ganze hier mal skizziert:
#include <algorithm> // copy #include <fstream> #include <iterator> // i(o)stream_iterator #include <iostream> #include <limits> // numeric_limits struct Eintrag { static int const N = 10; double prefix_; int ps_[N]; }; // -- Streaming-Operator für das Lesen // 1 "35.121: [Full GC (System) // 2 [PSYoungGen: 51172K->0K(764608K)] // 3 [PSOldGen: 0K->50789K(1747648K)] // 4 51172K->50789K(2512256K) // 5 [PSPermGen: 73515K->73515K(147072K)], // .. Rest bis EOL" std::istream& operator>>( std::istream& in, Eintrag& e ) { const std::streamsize ALL = std::numeric_limits< std::streamsize >::max(); in >> e.prefix_; in.ignore( ALL, ':' ); // ersten ':' hinter 'prefix' überspringen const char* tags = ":(>(]>(:>("; const char* tag = tags; for( int i=0; i<Eintrag::N; ++i, ++tag ) in.ignore( ALL, *tag ) >> e.ps_[i]; return in.ignore( ALL, '\n' ); // Rest der Zeile überlesen } // -- Streaming-Operator für das Schreiben std::ostream& operator<<( std::ostream& out, const Eintrag& e ) { out << e.prefix_ << " "; std::copy( e.ps_, e.ps_ + Eintrag::N, std::ostream_iterator< int >( out, " " ) ); return out; } int main() { using namespace std; ifstream f1("test.txt"); ofstream f2("backtest.txt"); if( !f1.is_open() || !f2.is_open() ) { cerr << "Fehler beim Oeffnen einer der Dateien" << endl; return -2; } copy( istream_iterator< Eintrag >(f1), istream_iterator< Eintrag >(), ostream_iterator< Eintrag >(f2, "\n") ); return 0; }Gruß
WernerUps: SeppJ war schneller, aber ich habe alle Zahlen

@Edit: Schleife beim Lesen
-
Na ja aus den Zahlen wollte ich dann nachher eventuell ein kleines Diagramm zeichnen lassen.

Aber so weite Schritte kann ich nicht überblicken, daher wollte ich in kleinen Schritten vorrangehen.
Man hat mir auch schon gesagt das Java besser gewesen wäre, aber ich wollte halt was in c++ machen da ich java nicht kann um da etwas fitter zu werden und dan kam mir halt so eine "hirnrissige idee" mit dieser Datei

-
Ihr seid ja mal der Hammer ich doktor da Wochen dran rum und Ihr braucht 5 Minuten

irgendwie deprimiert das:)Auf jeden fall ma herzlichen Dank
-
FillColin schrieb:
Man hat mir auch schon gesagt das Java besser gewesen wäre, aber ich wollte halt was in c++ machen da ich java nicht kann um da etwas fitter zu werden und dan kam mir halt so eine "hirnrissige idee" mit dieser Datei

Mit Java hast du keine Vorteile - eher mit Python/Perl/Ruby oae.
-
zum Einlesen des Eintrags ist mir noch eine weit lustigere Variante eingefallen, als mein erster Vorschlag oben:
// -- Streaming-Operator für das Lesen // 1 "35.121: [Full GC (System) // 2 [PSYoungGen: 51172K->0K(764608K)] // 3 [PSOldGen: 0K->50789K(1747648K)] // 4 51172K->50789K(2512256K) // 5 [PSPermGen: 73515K->73515K(147072K)], // .. Rest bis EOL" std::istream& operator>>( std::istream& in, Eintrag& e ) { in >> e.prefix_; // +--- Zeichen für 'Zahl lesen' // |+-- lese bis zum folgenden Zeichen // || |3 |4 |5 const char* format = "%_:[_[_:%_(%_)_->%K(%K)]%K->%K(%K)[_:%K->%K(%K)]_\n"; int i=0; for( const char* p = format+2; *p; ++p ) *p == *format ? in >> e.ps_[i++]: *p == *(format+1)? in.ignore( std::numeric_limits< std::streamsize >::max(), *++p ): in >> check( *p ); return in; }Dazu braucht man noch die
struct check:struct check { check( char c ) : c_( c ) {} friend std::istream& operator>>( std::istream& in, check ch ) { char c; if( in >> c && c != ch.c_ ) in.setstate( std::ios_base::failbit ); return in; } private: char c_; };Die Variante ist sicherer, was den Syntax-Check angeht, und auch universeller einsetzbar.
Gruß
Werner
-
jetzt noch mit tmp? ist ja nicht viel anders als brainfuck... :p
-
Na ja mit dem letzten code kann ich mal gar nichts anfangen, da verbiegen sich bei mir die Hirnwindungen
, leider bin ich ja auch noch lange nicht so fit wie ihr 
_____________________________________________Aber hätte noch eine Frage???

Warum muss ich "FETT" das nochmal aufrufen und ohne File Angabe? Oder ist das nur ein Platzhalter?
copy( istream_iterator< Eintrag >(f1), istream_iterator< Eintrag >(), ostream_iterator< Eintrag >(f2, "\n") );
Werner Salomon schrieb:
Hallo Fill,
... copy( istream_iterator< Eintrag >(f1), istream_iterator< Eintrag >(), ostream_iterator< Eintrag >(f2, "\n") );...
-
FillColin schrieb:
Warum muss ich "FETT" das nochmal aufrufen und ohne File Angabe? Oder ist das nur ein Platzhalter?
copy( istream_iterator< Eintrag >(f1), istream_iterator< Eintrag >(), ostream_iterator< Eintrag >(f2, "\n") );
Das copy muss wisssen, bis wohin kopiert werden soll. Ein istream_iterator ohne Streamargument im Konstruktor steht für das Ende eines Streams. Siehe:
http://www.cplusplus.com/reference/std/iterator/istream_iterator/
http://www.cplusplus.com/reference/algorithm/copy/
-
FillColin schrieb:
Na ja aus den Zahlen wollte ich dann nachher eventuell ein kleines Diagramm zeichnen lassen.

Man hat mir auch schon gesagt das Java besser gewesen wäre, aber ich wollte halt was in c++ machen da ich java nicht kann um da etwas fitter zu werden und dan kam mir halt so eine "hirnrissige idee" mit dieser Datei

Du solltest uns etwas mehr über deine Ziele mitteilen.
Zahlenwerte aus einer Datei rauslesen, geht so gut wie mit jeder Programmiersprache und sogar mit Applikationen.Nimm eine Tabellenkalkulation Excel oder OpenOffice:
- Kann auch Diagramme erzeugen
- Kann strukturierte Text-Dateien einlesen
-
Nochmal Hallo,
alles funktioniert nun einwandfrei *freu*
--- Auf basis von "Werner Salomon" 22:41:49 05.07.2012---Nur hat meine Aufzeichnung nun einen "kritischen Wert" erreicht.
126032.403: [Full GC (System) [PSYoungGen: 2400K->0K(764608K)] [PSOldGen: 58257K->51512K(1747648K)] 60657K->51512K(2512256K) [PSPermGen: 81683K->81341K(82112K)], 0.3413080 secs] [Times: user=0.34 sys=0.00, real=0.34 secs]
Wenn nun mein Zeitstempel immer größer wird "FETT", dann ist nachher nur noch 126032 zu sehen. Der rest .403 wird verschluckt.
Nun habe ich versucht im Programm die Datentypen zu vergrößern also "long", dies hatte aber nicht den gewünschten Erfolg.
Dann habe ich mal etwas mit Zahlen gespielt
z.b. 200000000 der wird schön ausgegeben, aber sobald was mit Komma kommt schmeist der das weg z.B. 200000000.222Kann es sein, dass das Programm automatisch castet und rundet und wenn ja wie unterbinde ich das?
Scchöne Grüße
Fill
-
float und double sind mMn. denkbar schlechte Typen für Zeitstempel. Zumindest wenn der Zeitstempel exakt gespeichert/verarbeitet werden soll. Das geht mit float/double nämlich nur, wenn die binäre (!) Darstellung der Kommazahl ausreichend wenig signifikante Stellen hat.
Was noch dazukommt: je nach verwendeter Funktion (printf, operator << (ostream, ...), ...) werden floats/doubles per Default unterschiedlich genau formatiert. Und das kann eben dazu führen, dass Kommastellen die eigentlich da wären einfach nicht angezeigt werden.
Kann man natürlich alles mittels diverser Formatierungs-Optionen umstellen, aber es bleibt immer noch das Problem dass sich Dezimal-mit-Kommastellen nicht gut mit Binär-mit-Kommastellen verträgt.
-
Hallo Fill,
hustbaer hat wahrscheinlich recht mit seinem Verdacht, dass es sich nur um ein Darstellungsproblem handelt. Ein double reicht für 126032.403 locker aus.
Füge in meinem Listing vor dem 'copy( istream_iterator<>..' noch eine Formatierung für double ein:f2.precision(3); f2 << fixed; copy( istream_iterator< Eintrag >(f1), istream_iterator< Eintrag >(), ostream_iterator< Eintrag >(f2, "\n") );Damit erzwingst Du, dass double mit 3 Nachkommastellen ausgegeben wird.
Gruß
Werner
-
Danke für die thematisch Erörterrung!!
Sind diese Delauft-Werte in denen automatisch und unterschiedlich Formatiert wird eigentlich willkürlich ausgedachte Standardts oder entspricht das einer durchdachten Norm von c++.
Habe ich nur das Gefühl, dass das suboptimal ist oder ist meine Aufgabe eher Suboptimal

Dabei dachte ich das c++ mehr Vorgaben/-schriften bekommen hat wie C um es "sicherer/einfacher" zu machen und nun muss ich quasi doch so spitzfindig sein?

____________________________________________
Auf jeden fall super lieben Dank für die Komments bis jetzt, ihr habt mich echt weitergebracht und es macht sogar richtig spaß in diesem ForumGrüße
-
Der Anfangswert für precision ist laut Standard als 6 definiert.
-
FillColin schrieb:
Dabei dachte ich das c++ mehr Vorgaben/-schriften bekommen hat wie C um es "sicherer/einfacher" zu machen und nun muss ich quasi doch so spitzfindig sein?

Nein, du musst bloss den passenden Datentyp verwenden

-
Hallo, ich bin's wieder.
zu meiner Freude läuft das Programm auf basis von WERNER SALOMON (Thread 12:43:51 05.07.2012) einwandfrei und konnte es gut weiterverarbeiten.
Nun habe ich feststellen müssen, das in meine Textdatei 1 mal im Monat ein Sondereintag (Sonderprüfung) stadtfindet. Und zwar kein Full GC sondern nur ein CG
....
3636.211: [Full GC (System) [PSYoungGen: 6520K->0K(764608K)] [PSOldGen: 50789K->56413K(1747648K)] 57309K->56413K(2512256K) [PSPermGen: 82267K->82267K(172288K)], 0.3546920 secs] [Times: user=0.35 sys=0.00, real=0.36 secs]
7237.275: [GC [PSYoungGen: 91438K->2416K(764608K)] 147852K->58829K(2512256K), 0.0123960 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
7237.287: [Full GC (System) [PSYoungGen: 2416K->0K(764608K)] [PSOldGen: 56413K->58662K(1747648K)] 58829K->58662K(2512256K) [PSPermGen: 82381K->82381K(170048K)], 0.3349310 secs] [Times: user=0.33 sys=0.00, real=0.34 secs]
...Ab hier bricht das Programm dann ab

_____________________________________
Wie ich aus der Zeile GC meine gewünschten Zahlen herausbekomme weiß ich nun dank euch.Nur wie kann ich in das Programm einbauen, dass die Zeilen vorab geprüft werden ob ein FullGC oder ein GC vorliegt, um dann mit einem passenden Copy(...); darauf zu reagieren.
int main() { using namespace std; ifstream f1("test.txt"); ofstream f2("backtest.txt"); if( !f1.is_open() || !f2.is_open() ) { cerr << "Fehler beim Oeffnen einer der Dateien" << endl; return -2; } struc.precision(3); // 3 Nachkommastelen erzwingen struc << fixed; // Keine expot. Darstellung => Ganzzahl copy( istream_iterator< Eintrag >(f1), istream_iterator< Eintrag >(), ostream_iterator< Eintrag >(f2, "\n") ); return 0; }Habe mir überlegt, ob ich zwischen Zeile 10 und 14 irgendwie die Zeile Abfrage, dann prüfe und dann mit einer IF-Schleife in den passenden Coppy(..); gehe.
Aber ich muss das irgendwie immer Zeilenweise machen und nicht die gesammte Datei...hm...Hat mir eventuell jm. einen Gedankengang wie ich das umsetzen könnte?
Herzlichen Dank schon mal
Fill
-
FillColin schrieb:
Habe mir überlegt, ob ich zwischen Zeile 10 und 14 irgendwie die Zeile Abfrage, dann prüfe und dann mit einer IF-Schleife in den passenden Coppy(..); gehe.
Hallo Fill,
wenn Du eine Änderung machen willst (und das gilt immer bei Programmänderungen), so solltest Du zunächst feststellen, welches Modul/Funktion für diese Funktionalität, die Du ändern willst, verantwortlich ist.
Was Du hier vorhast, ist das Einlesen zu ändern. Das Einlesen geschieht im Streaming-Operator vonstruct Eintrag; also ist da die Baustelle, nirgendwo sonst.Wenn man die lustige Variante, die ich bereits gepostet habe, weiter entwickelt, so kann sie auch das.
#include <algorithm> // copy #include <fstream> #include <iterator> // i(o)stream_iterator #include <iostream> #include <limits> // numeric_limits #include <string> struct check { check( char c ) : c_( c ) {} friend std::istream& operator>>( std::istream& in, check ch ) { char c; if( in >> c && c != ch.c_ ) in.setstate( std::ios_base::failbit ); return in; } private: char c_; }; struct Eintrag { static int const N = 10; double time_; int ps_[N]; }; // -- Streaming-Operator für das Lesen // einiger(!) Logging Ausgaben des Garbage Collectors von Java // Bem.: PS := Parallel Scavenge (scavenge -> Reinigung) // // Format: (Beispiel, im Orginal einzeilig) // 35.121: // [Full GC (System) // [PSYoungGen: 51172K->0K(764608K)] // [PSOldGen: 0K->50789K(1747648K)] // 51172K->50789K(2512256K) // [PSPermGen: 73515K->73515K(147072K)], // .. Rest bis EOL // // -oder: // 7237.275: // [GC // [PSYoungGen: 91438K->2416K(764608K)] // 147852K->58829K(2512256K), // .. Rest bis EOL // std::istream& operator>>( std::istream& in, Eintrag& e ) { const std::streamsize ALL = std::numeric_limits< std::streamsize >::max(); std::string token; (in >> e.time_).ignore( ALL, '[' ) >> token; const char* format = token == "Full"? // +--- [0] Zeichen für 'Zahl lesen' // |+-- [1] lese bis zum folgenden Zeichen // ||+- [2] nächstes Element mit 0 belegen // ||| // |||<- Young --><- Old --><-- nn --><--- Perm ---> "%_#_[_:%K_(%K)][_>%K(%K)]%K->%K(%K)[_:%K->%K(%K)]_\n": // Full GC (System) "%_#_[_:%K_(%K)]" "##" "%K->%K(%K)" "###" "_\n"; // GC int* dst = e.ps_; for( const char* p = format+3; *p; ++p ) { if( *p == format[0] ) in >> *dst++; else if( *p == format[1] ) in.ignore( ALL, *++p ); else if( *p == format[2] ) *dst++ = 0; // Eintrag hier nicht vorhanden else in >> check( *p ); } return in; } // -- Streaming-Operator für das Schreiben std::ostream& operator<<( std::ostream& out, const Eintrag& e ) { out << e.time_ << " "; std::copy( e.ps_, e.ps_ + Eintrag::N, std::ostream_iterator< int >( out, " " ) ); return out; } int main() { using namespace std; ifstream f1("test.txt"); ofstream f2("backtest.txt"); if( !f1.is_open() || !f2.is_open() ) { cerr << "Fehler beim Oeffnen einer der Dateien" << endl; return -2; } copy( istream_iterator< Eintrag >(f1), istream_iterator< Eintrag >(), ostream_iterator< Eintrag >(f2, "\n") ); return 0; }beachte bitte, dass ich die gelesenen Zahlen nicht einfach in das Feld von
Eintragfülle, sondern zunächst noch zwei Elemente mit 0 belege. Das ist dann der fehlende Eintrag für das Feld[PSOldGen].
In den Zeilen 60 und 61 habe ich das Format fürFull GCundGCdefiniert.
Wenn Du dazu Fragen hast, so nur heraus damit.Gruß
Werner
-
Hallo Werner,
danke für die Antwort. Ich hatte zu beginn bewusst deine "lustige Variante" nicht genomme, da ich leider nur 40% davon verstanden habe. Also den "struct check" und den "streaming operator".
Wenn du mir allerdings anbietest meine Fragen dazu zu beantworten, dann werde ich ihn wohl einsetzen, weil ich grundsätzlich nur das verwenden will was ich auch verstehen und handhaben kann.
__________________________________
Ich würde mich bei den Zeilenangaben auf deinen letzten Post beziehen.8-20 Ich verstehe nicht warum nach dem friend(11) eine Schachtelung erfolgt und was diese bewirkt (12 u. 17)
18-19 Also private kenn ich, aber in der Form habe ich das noch nie eingesetzt. Sondern nur wenn ich ne Klasse private oder public gemacht habe. Daher erschließt sich mir der Teil nicht, da er mittem im struct ist.
54 Was bezweckt diese Zeile mit dem Gleich und dem Vergleich-Operator?
63-73 Ich kann mit zwar zusammenreimen was die Funktion macht und die Erklärung von dir bestätigt das auch, aber die Frage ist wie macht sie das.
In der for-schleife prüfst du ja ob % oder _ oder # vorhanden ist.
Pointer / Zeiger kenne ich zwar auch, aber da ich nicht so fit bin verbiegt es hier meine Hirnwindungen
Und allgemein, bzum Leseoperator.
Betrachtet er eine Zeile und springt dann in die nächste ? (wenn ja wie? wo? oder macht das die for schleife)
Oder geht er das Dokument auf einmal durch und merkt dann wenn die Zeile zuende ist?
_____________________________________________
Es tut mir sehr leid wenn ich so viele Fragen stelle, leider ist dieser Programmcode doch zu hoch für mich, um ihn in seiner Gesammtheit zu überschauen.Auf jeden Fall herzlichen Dank für die Mühe deinerseits
Grüße
Fill
-
FillColin schrieb:
8-20 Ich verstehe nicht warum nach dem friend(11) eine Schachtelung erfolgt und was diese bewirkt (12 u. 17)
Die Schachtelung kommt von der Funktion die in Zeile 11 anfängt. Das friend bezieht sich auf diese Funktion. Die Funktion hat einen etwas ungewöhnlichen Namen, operator>>, ist aber ansonsten eine Funktion wie jede andere auch. Der ungewöhnliche Name macht, dass man sie später auch mittels
istreamobjekt >> checkobjekt;aufrufen kann, anstatt nur mit
operator>>(istreamobjekt, checkobjekt);. Das nennt man Operatorüberladung.
Beachte, dass die Funktion kein Member von check ist. Das friend macht an dieser Stelle nicht nur, dass die Funktion auf die privaten Member von check zugreifen kann, sondern auch, dass sie frei im Namensraum von check liegt, obwohl sie in check definiert wird.
18-19 Also private kenn ich, aber in der Form habe ich das noch nie eingesetzt.
Dann kennst du private nicht wirklich, denn hier hat es genau die gleiche Bedeutung wie anderswo, denn es gibt nur eine Bedeutung.
Sondern nur wenn ich ne Klasse private oder public gemacht habe.
Man kann keine Klassen private oder public machen, sondern nur gewisse Member. Verwirrt dich das struct? struct und class sind in C++ das gleiche, einziger(!) Unterschied ist, bei class ist alles private, sofern man es nicht public macht, bei struct ist alles public, solange man es nicht private macht. (Oder protected, was ich jetzt mal unterschlagen habe, ist überall noch eine dritte Möglichkeit)
Daher erschließt sich mir der Teil nicht, da er mittem im struct ist.
Dann hast du private und public wirklich nicht verstanden. Da check ein struct ist, ist alles was vor dem private steht public, das ist in diesem Fall nur der Konstruktor in Zeile 10 (der friend in Zeile 11 ist sowieso keine Memberfunktion und nicht betroffen von public/private, siehe oben). Alles nach dem private ist private, also der Member c_ ist von außen unsichtbar.
54 Was bezweckt diese Zeile mit dem Gleich und dem Vergleich-Operator?
Das ist eine Zeile bis einschließlich 62.
Du kennst den ternären Operator?
a = b ? c : d;Das ist eine andere Schreibweise für
if (b) a = c; else a = d;Da steht also:
if (token == "Full"?) format = "%_#_[_:%K_(%K)][_>%K(%K)]%K->%K(%K)[_:%K->%K(%K)]_\n"; else format = "%_#_[_:%K_(%K)]" "##" "%K->%K(%K)" "###" "_\n";63-73 Ich kann mit zwar zusammenreimen was die Funktion macht und die Erklärung von dir bestätigt das auch, aber die Frage ist wie macht sie das.
In der for-schleife prüfst du ja ob % oder _ oder # vorhanden ist.
Pointer / Zeiger kenne ich zwar auch, aber da ich nicht so fit bin verbiegt es hier meine Hirnwindungen
Ich behaupte mal, wenn ich es dir erkläre, verstehst du es nicht oder die Erklärung wird lang wie ein Lehrbuch. Daher: Lies erst einmal ein Lehrbuch, bis du weißt, wie die Streams funktionieren und ein bisschen über Pointerarithmetik. Wichtig ist, dass es ein gutes Buch ist, sonst werden die Streams nicht richtig erklärt (dafür wird aber wahrscheinlich viel zu viel Gewicht auf Pointer gelegt :p ). Siehe zweiter Link in meiner Signatur.
Und allgemein, bzum Leseoperator.
Welchem? Der Code definiert gerade zwei eigene Operatoren, die jeweils unzählige verschiedene andere Leseoperatoren benutzen. Ich nehme mal an, du meinst den in Zeile 49:
Betrachtet er eine Zeile und springt dann in die nächste ? (wenn ja wie? wo? oder macht das die for schleife)
Er liest so lange, wie das Format stimmt. Da das Format mit einem Zeilenumbruchzeichen endet (siehe Zeilen 61 und 62), wird er bei Erfolg eine ganze Zeile gelesen haben. Bei Misserfolg wird er irgendwo stehen bleiben. Er endet aber nicht prinzipbedingt auf dem Zeilenende, sondern wirklich nur wegen des Formatstrings der hier so gegeben ist. Zeilenumbrüche sind keine besonderen Zeichen für den Computer, die Sonderrolle die du ihnen zusprichst kommt allein aus ihrer üblichen Darstellung auf dem Bildschirm.