Textdatei gezielt bearbeiten (Nur bestimmte Werte)
-
Guten Tag,
ich schreibe zur zeit an meiner bachelorarbeit und komme mit einem Problem leider nicht weiter. hab schon stundenlang mit suche im netz verbracht leider ohne erfolg.
ich will ein text file (ab jetzt original datei genannt) das verschiedene informationen beinhaltet mit einem c++ code einlesen und bearbeiten.
Mit bearbeiten meine ich speziell eine eizige spalte in der die werte drinstehen die mich interessieren. Diese besagten werte stehen ausschließlich in der letzten spalte in der original datei.Dann will ich die bearbeiteten werte in ein neue datei schreiben.
mein bisheriger code macht auch schon das was ich will leider nur an einer test Datei, und ich weiß nicht wie ich das mit der original file geht.
Die sieht nämlich etwas anders aus als meine test file mit der ich meinen code geschrieben habe.
Ich hoffe jetzt versteht man mich etwas besser.Das ist die original datei die ich bearbeiten will die werte in der letzten spalte sind die benötigten werte. also quasi 3.2472 dann 3.1072 usw.
Node Number X Location (mm) Y Location (mm) Z Location (mm) Maximum Principal Stress (MPa) 1 76.562 85.819 18. 3.2472 2 76.562 85.819 16. 3.1072 3 76.562 85.819 14. 3.007 4 76.562 85.819 12. 2.9468 5 76.562 85.819 10. 2.9267 6 76.562 85.819 8. 2.9468 7 76.562 85.819 6. 3.007 8 76.562 85.819 4. 3.1072 9 76.562 85.819 2. 3.2472 10 76.097 84.809 18. 3.3836Der C++ code macht folgendes: ich lese die werte der test Datei und ersetzte alle zahlen die kleiner sind als ein zuvor abgefragter wert durch die null. Eigentlich ganz einfach.
Mein bisheriger code sieht so aus:
#include <iostream.h> #include <stdlib.h> #include <conio.h> #include <fstream.h> #include <math.h> void main(){ float spannung, wert; char dateiname[41]; ifstream quelle; ofstream ziel; //Öffnen der Datei zum Lesen quelle.open("vergl.txt", ios::nocreate); //Fehler beim öffnen ? if(quelle ==0) { cout<<"vergl.txt kann nicht geoeffnet werden." <<endl; getch(); exit (-1); } //Frage nach Dateiname cout <<"Bitte geben Sie den Dateinamen fuer die Ausgabe ein"<<endl; cout <<"Bitte Dateinamen ohne Leerzeichen eingeben: "<<endl; cin>>dateiname; //Öffnen der Datei zum schreiben ziel.open(dateiname, ios::noreplace); //Fehler beim Öffnen ? if (ziel ==0) { cout<<dateiname<< " kann nicht geoffnet werden."<<endl; getch; exit (-1); } //Einlesen des ersten Wertes quelle>>spannung; cout<<"Ab welchen Wert sollen die Spannungen Null gesetzt werden?"<<endl; cin>>wert; //Schleife bis Dateiende erreicht ist // Alle Spannungen umter (Wert) werden Null gesetzt !!! :-)) while (quelle.eof()==0) { if((spannung < wert)) { spannung = 0.0; }else(spannung = spannung); ziel << spannung <<endl; quelle >> spannung; } //vergl.txt und Ausgabedatei schließen quelle.close(); ziel.close(); cout<<"Das Programm ist fertig. " <<endl; system("PAUSE"); }der code funktioniert auch ganz gut nur leider noch nicht bei der original Datei sondern nur bei meiner test datei:
34.708 34.6 34.523 34.476 34.461 34.476 34.523 34.6 34.708 34.698 34.595 34.521 34.477 34.463 34.477 34.521 34.595 34.698 34.45 34.342 34.265 34.218 34.203 34.218 34.265 34.342 34.45Kann mir einer bitte tips geben wie ich das hinbekomme das ich die original datei bearbeiten kann?
-
Verteile die folgenden Zeichen in deinem Beitrag, dann hat man vielleicht eine Chance, zu erraten, worum es geht und was du wissen moechtest:
,,,,,,,,,,,,,,,,,,,,,,,.................??????!!""""" AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ(Du musst nicht unbedingt alle diese Zeichen benutzen und falls dir dringend eines von einer Sorte fehlt, darfst du auch grosszuegig mehr benutzen)
edit: Waehrend ich diesen sarkastischen Beitrag schrieb, hast du deinen Beitrag mehrmals ueberarbeitet. Er ist mittlerweile schon beinahe verstaendlich.
Wenn ich viel Zeit habe, versuche ich mal, ihn zu entziffern.
-
SeppJ schrieb:
Waehrend ich diesen sarkastischen Beitrag schrieb, hast du deinen Beitrag mehrmals ueberarbeitet. Er ist mittlerweile schon beinahe verstaendlich.
Wenn ich viel Zeit habe, versuche ich mal, ihn zu entziffern.
na dann bin ich ja guter dinge. ich versuche den beitrag noch ein wenig zu optimieren. versprochen.mfg.
denis978
-
Stehen in deiner Testdatei wirklich Kommas als Dezimaltrennzeichen?
Und das funktioniert?Die wohl beste Antwort ist: Lern awk. Du wirst jetzt vielleicht zuerst denken, dass das eine doofe Antwort waere, aber sie ist aus folgenden Gruenden hilfreich:
-awk ist nicht schwierig, sobald man die Grundlagen kennt. Bloss der allererste Einstieg ist vielleicht etwas schwer
-Es loest dein Problem mit den Spalten direkt
-Es loest nicht nur dein Problem mit den Spalten, sondern dein Gesamtproblem ist ein trivialer Einzeiler in awk
-Sehr viele andere Probleme dieser Art (alles mit Spalten) lassen sich damit ganz einfach loesen. Solche Probleme hat man sehr oft, daher ist es nuetzlich, ein gutes Werkzeug dafuer zu kennen (Intensive awk-Nutzer haben jedoch eine Tendenz, es als goldenen Hammer zu betrachten
)
-Wenn die Gesamtloesung nicht in einen awk-Einzeiler passt, weil die Rechnung etwas komplexer ist, kann man es auch wunderbar mit anderen Programmen kombinieren: Richtige Spalten raussuchen und eventuell bearbeiten mit awk, dann die awk-Ausgabe an das Hauptprogramm weiter leiten. Mit einer guten Konsole (nicht die Windows-Konsole) geht das besonders gut.Falls es unbedingt in C++ sein soll (C++ eher auf andere Einsatzzwecke optimiert), erst einmal ein paar Fehler/Schwaechen in deinem Code:
-Dein Compiler muss vorsintflutlich sein, wenn er den Code akzeptiert. Die C++-Standardheader haben seit ueber 15 Jahren kein ".h" am Ende des Namens. Ich empfehle dringend ein Update. 15 Jahre sind eine Ewigkeit fuer Computer. Gerade in den letzten Jahren hat sich viel rund um C++ getan.
-Aehnliches gilt fuervoid main. Das ist spaetestens seit 1998int main.
-Dafuer wurden 1998 namespaces eingefuehrt. Kennt dein Compiler anscheinend auch nicht
.
-nocreate gibt es auch nicht im 1998 eingefuehrten Standard-C++. Was benutzt du bloss? Mein Schuss ins Blaue: MSVC 6? Das waere tatsaechlich von 1998
. Wuerdest du auch Windows 98 einsetzen? Falls Nein: Wieso dann ein antiker Compiler und IDE? Wenn es MSVC sein soll: Die Expressedition von Visual Studio ist frei benutzbar. Die letzte ist von 2013! Es gibt auch mindestens zwei sehr gute freie Compiler (viele wuerden sogar sagen, GCC und Clang waeren die besten Compiler ueberhaupt) und einige gute freie IDEs.
-nocreate ist sowieso ueberfluessig, da es das Standardverhalten ist (zumindest heutzutage. Vor 1998 mag das vielleicht anders gewesen sein)
-Ein Vergleich eines Streams mit 0? Mag technisch sogar funktionieren, aber ich glaube, du verwechselst das mit FILE-Pointern aus C.
-exit raeumt in C++ nicht sauber auf! Mach doch einfach einreturn, wenn du in der main bist. Ansonsten wirf eine Exception.
-std::string wurde mittlerweile auch fuer Zeichenketten erfunden.
-Man muss auch schon lange nicht mehr alle Variablen am Anfang eines Scopes definieren. C++ ist nicht 1989er C. Dann waere dir auch aufgefallen, dass du die Haelfte der Variablen nicht benutzt.
-Fuer noreplace gilt aehnliches wie fuer nocreate. Bloss ist es etwas umstaendlich, das Flag 1:1 mit standardkonformen Mitteln zu ersetzen. Was soll denn passieren, wenn es die Datei schon gibt?
-Zeile 36 kann unmoeglich compilieren. Nicht einmal mit einem antiken Compiler. Hast du den Code im Foreneditor geschrieben? Copy & Paste nutzen! Sonst finden wir hier bloss lauter Fehler, die du beim Abschreiben gemacht hast.
-Eine Leseschleife sah in C++ noch nie so aus. Auch in C nicht. Und in allen aehnlichen Sprachen auch nicht. Darum ist das auch so umstaendlich mit dem Einlesen des ersten Wertes. Wenigstens pruefst richtigerweise nach dem Einlesen, ob es erfolgreich war. Immerhin etwas. Die uebliche Seuche ist naemlich, erst zu pruefen, dann zu lesen. Irgendein wahnsinnig schlechter Lehrer verbreitet das irgendwo.
-Kommt dir Zeile 54 nicht irgendwie umstaendlich vor?
-Gerade bei Ausgabe in Dateien, ist es wichtig, einen Zeilenumbruch ('\n') und endl (Zeilenumbruch + flush()) zu unterscheiden. Nach jedem Wert zu flushen ist saulangsam!
-Bloss weil in deinem Programm gerechnet wird, brauchst du uebrigens die Mathebibliothek nicht. In der Mathebibliothek stehen Funktionen wie Sinus, Wurzel und aehnliches. Plus und Minus kann C++ auch schon so :p .
-Dateien in C++ schliessen sich automatisch, wenn sie aus dem Scope gehen.Die allererste Ueberarbeitung deines Codes:
#include <iostream> #include <cstdlib> #include <fstream> #include <string> using namespace std; int main() { //Öffnen der Datei zum Lesen istream quelle.open("vergl.txt"); //Fehler beim öffnen ? if(!quelle) { cout<<"vergl.txt kann nicht geoeffnet werden.\n"; return -1; } //Frage nach Dateiname cout <<"Bitte geben Sie den Dateinamen fuer die Ausgabe ein\n"; cout <<"Bitte Dateinamen eingeben: "; string dateiname; getline(cin, dateiname); //Öffnen der Datei zum schreiben ostream ziel(dateiname); // Oder dateiname.c_str() vor C++11. //Fehler beim Öffnen ? if (!ziel) { cout<<dateiname<< " kann nicht geoffnet werden.\n"; return -1; } cout<<"Ab welchen Wert sollen die Spannungen Null gesetzt werden? "; float schwellwert, spannung; cin>>schwellwert; //Schleife bis Dateiende erreicht ist // Alle Spannungen umter (Wert) werden Null gesetzt !!! :-)) while (quelle >> spannung) { if((spannung < schwellwert)) spannung = 0.0; ziel << spannung << '\n'; } cout<<"Das Programm ist fertig.\n"; }Da der Beitrag gerade irre lang wird, mache ich hier mal einen Bruch. Weiter geht es nach der naechsten Maus.
-
Hier eine Ueberarbeitung deines Programms, die gut mit awk zusammen arbeitet:
#include <iostream> #include <sstream> #include <string> using namespace std; void usage(const char* progname) { cerr << "Bitte Schwellwert angeben:\n" << progname << " schwellwert\n"; } int main(int argc, char* argv[]) { if (argc <= 1) { usage(argv[0]); return -1; } double threshold; { stringstream parse_threshold(argv[1]); if (!(parse_threshold >> threshold)) { usage(argv[0]); return -1; } } for (double value; cin >> value;) { if(value < threshold) value = 0.0; cout << value << '\n'; } cerr <<"Das Programm ist fertig.\n"; }Sieht doch schon eine ganze Ecke einfacher aus, alleine dadurch, dass man die Unix-Philosophie beachtet und einen Filter schreibt. Das Programm kommt sowohl mit deinen Testdaten klar (wobei man fuer Komma als Trennzeichen die Systemlocale aendern muss) als auch - wenn man mit awk einen anderen Filter davor schaltet - mit deiner Originaldatei. Wenn man die erste Zeile mal weg laesst (zum Beispiel, indem man sie mit tail filtert), dann koennte ein Aufruf so aussehen (bash-Syntax, die Windows-Kommandozeile wird aehnlich oder genauso gehen):
awk < test.dat '{print $5}' | programm 2.95Mit awk alleine saehe das Ganze uebrigens so aus (wieder angenommen, dass die erste Zeile schon weg ist, ansonsten kann man das auch mit awk machen):
awk < test.dat '{print ($5 < 2.95) ? 0 : $5}'Daran sieht man vielleicht auch, wieso ich oben awk alleine fuer diese Aufgabe empfohlen habe
. Dein Gesamtproblem wird mit wenigen Zeichen(!) Quelltext geloest.Und wie ginge das nun in reinem C++? Da ich jetzt schon ziemlich viel geschrieben habe, fasse ich mich da mal kurz: Diese Aufgabe kann man entweder elegant loesen (ist aber was fuer Fortgeschrittene) oder quick&dirty hacken. Fragen dieser Art gab es hier im Forum schon sehr oft, meistens wurden dann beide Wege als Antwort gezeigt. Fuer elegante Loesungen zu schwierigen Parseproblemen empfehle ich die Beitraege von Nutzer "Werner Salomon". Dessen Beitraege kannst du ueber das Autorenfeld in der Forensuche finden. Da sind auch viele Beitraege ueber spaltenbasierte Formate dabei, mit und ohne Kommentare zwischen den Daten, mit Punkt oder Komma als Dezimaltrennzeichen.
-
Super Beitrag

-
Wow echt ein Hammer Beitrag, werde mich gleich mal daran setzen und versuchen das richtig zu verstehen. Bin leider gerade unterwegs. Erst mal danke. Bis später.
Mfg.
-
Hallo SeppJ,
jetzt habe ich etwas Zeit und ich will mich mal deiner Kritik stellen.
Das mit dem Komma ist natürlich mein Fehler der Code den ich gepostet habe geht so natürlich nicht.
Ich hab meine Testdatei auch erst angepasst und punkte statt Kommas in dieser Datei stehen. Das habe ich auf Windows 8.1 über die Region Einstellungen geschafft. Das FEM Programm das mir die Original Datei liefert hat sonst nämlich immer alles mit Kommas getrennt nach den Regional Einstellungen hat das mit dem Punkten als Trennzeichen zumindest schon geklappt.
Ich wollte zuerst mit einem Code alle Kommas durch Punkte ersetzten lassen, jedoch habe ich einen Beitrag hier im Forum gefunden in dem dringend von so einem vorhaben abgeraten wird (wegen ugly Code usw..), also habe ich es dann sein lassen.
Leider habe ich, als ich den Code gepostet habe, nicht gemerkt das ich noch die Variablen die ich dazu deklariert hatte nicht wieder entfernt habe. Mittlerweile habe ich das allerdings nicht mehr in meinem Code stehen.Zu meinem Compiler und meinen generellen C++ bzw. Programmierer Kenntnissen:
Ich bin im Moment im letzten Semester im Bereich Maschinenbau an einer Technischen Hochschule in Bayern. Dort habe ich erst vor 1.5 Jahren gelernt wie man überhaupt Programmiert, zuvor hatte ich gar keine Kenntnisse in diesem Bereich. Mein Professor ist leider einer von der alten Schule und hat uns tatsächlich diese alte Syntax, an dem Borland v5.02 (Baujahr 1997) genau so wie ich es geschrieben habe beigebracht.
Ich habe dem MSVS Professional 2013 als Studentenversion auf meinem Rechner installiert und hatte ursprünglich vor das Programm mit diesem modernen Compiler zu schreiben. Allerdings habe ich gestern sehr große Probleme bekommen denn der MSVS 2013 hat fast in jeder Zeile irgendwelche Fehler erkannt und wollte das Programm so in dieser Form nicht ausführen. Leider bin ich nicht der Überflieger im Programmieren weshalb ich mich dazu entschied wieder den alten Borland zu nutzen.Wie es jetzt weitergeht:
Im Moment denke ich zumindest ernsthaft darüber nach mich mit dem MSVS auseinanderzusetzten, allerdings weiß ich nicht ob ich das tatsächlich schaffe. Am liebsten wäre es tatsächlich wenn ich das im Borland realisieren könnte dennoch muss ich ehrlicherweise eingestehen das es auf lange Sicht unabdingbar ist den Umstieg zu schaffen.
Ich danke dir sehr für deine Mühen und muss mir jetzt mal ein paar Gedanken über mein weiteres Vorgehen machen. Deinen überarbeiteten Code verstehe ich im Moment fast gar nicht, in diesem Code ist so ziemlich alles anders als das was ich gelernt habe. Ich glaube dir auch das es so besser, moderner, Fehlerunauffälliger usw. geht, aber Fakt ist, ich muss mir das mal richtig reinziehen damit ich überhaupt verstehe was in deinem Code, Zeile für Zeile passiert.
Gar nicht so einfach wenn man nur die Steinzeit Methoden von meiner Informatik Vorlesung kann
.Mit freundlichem Gruß
denis978
P.S. Ich hab soeben die Testdatei im ersten Beitrag soweit überarbeitet das zum einen die Kommas durch Punkte ersetzt wurden und zum anderen die überflüssigen Variablen aus dem C++ Code draußen sind.
-
Ich würde dir auf jeden Fall empfehlen, nicht mit dem uralten Borland weiter zu arbeiten. Das moderne C++ ist keine Eigenart des neuen MSVC. C++ ist eine standardisierte Sprache mit einer eigenen ISO-Norm (eben seit dem oft erwähnten Jahr 1998). Alle Programme, die nach dieser Norm geschrieben wurden, sind mit jedem Compiler auf jedem System übersetzbar, sofern der Compiler sich auch an diese Norm hält (und das tun sie alle*). Dieses C++ ist es auch, was du in jedem modernen Lehrbuch lernst. Du ist also gut beraten, dir diese Sprache anzueignen, anstatt einen ähnlichen, aber inkompatiblen, Dialekt zu lernen, mit der du dann irgendeinen Uralccompiler von 1997 programmieren kannst.
Der C++-Standard wurde seit 1998 mehrmals ergänzt (TR1 und C++11, die nächste geplante Ergänzung ist C++14), aber aus Anfängersicht hat sich nicht so viel zu C++98 verändert. Wenn du aber ohnehin den Dialekt wechselst, ist es trotzdem zu empfehlen, dass du guckst, dir vielleicht ein neues Lehrbuch nach C++11 zu besorgen. Falls du keines bekommst, guckst du dir später einfach mal die Neuerungen an, nachdem du die Grundlagen richtig kannst.
*: Bis auf ein paar kaum bekannte Sprachfeatures, die kaum jemand kennt oder nutzt.
-
Eigentlich eine Schweinerei jemanden heute noch den alten Mist beizubringen wenn mir das so in dieser Form im weiteren Berufsleben nichts nutzen wird. Das nächste ist das ich mich mit "Informatik für Ingenieure" über zwei Semester an unserer Hochschule recht schwer getan habe und jetzt nur Uralt Compiler Programmieren kann.
Naja egal, jedenfalls nett von dir mir die Augen geöffnet zu haben. Jetzt weiß ich zumindest das ich da noch mal was machen muss. Auch das es sozusagen verschiedene Dialekte einer Programmiersprache gibt ist mir bis jetzt nicht bekannt gewesen.
Mfg.
-
denis978 schrieb:
Auch das es sozusagen verschiedene Dialekte einer Programmiersprache gibt ist mir bis jetzt nicht bekannt gewesen.
Eigentlich gibt es die ja gerade nicht. Beziehungsweise bei vielen Sprachen schon, aber bei C++ nicht. Ebenso gibt es solche Normen fuer andere bedeutende Sprachen, wie C; Sprachen die einmal bedeutend waren, wie COBOL; oder Quasistandards, da hinter der Sprache ein grosses Unternehmen steht (anstatt der ISO), welches die Richtung vorgibt, wie Java.