Nur bestimmte Zahlen aus Textdatei auslesen


  • Mod

    out schrieb:

    kannst du mehr Informationen zum Dateiaufbau geben?

    👍
    Je nachdem, wie die Datei aufgebaut ist, kann man sich bestimmte Konstellationen zum Vorteil nehmen um das Parsen zu vereinfachen. So kann man bspw. nicht nach Coord, sondern nach C suchen.

    Sobald du die Position gefunden und gesetzt hast, könntest du einen Trick anwenden, um dir das Parsen zu erleichtern. 🤡 🤡

    stream.ignore(6); // Coord: überspringen
    std::complex<int> c;
    stream >> c; // Die in Klammern eingeschlossenen Zahlen extrahieren
    

    Beide Zahlen bekommst du durch die Member real und imag .



  • Auszug aus der Datei:

    TTFis:\>TR_CONVERT_FILE
    proxyfile@cardProxy mode: Flush
    proxyfile@cardReplaying file is F:\proxy_trace1.bin
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_DEAD_RECKONING_POSITION->STATUS) State: VALID, Time: 27282, Posix: 27s+625ms, Pos: (-921911768,515242529) (Err:375,159,1), Head: 231 (Err:5023), Turnrate: 0 (Err:0), Speed:0 (Err:0), Accel: 0 (Err:0), Height: 0 (Err:2), Sensors: prov:15, det:6, used:6, cal:0
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_EXTRAPOLATED_POSITIONS->STATUS) Dataset:0 RelID:4294967295 Rel:17 Time:28,362 Int:40 NumPts:50: Coord:(3373055528,515242529) Head:15964 Angl:15964 Speed:0 E7 4F 00 00 22 5E AD 02 00 00 00 00 FF FF 28 BE 0C C9 21 FA B5 1E 5C 3E 5C 3E 00 00 E7 4F 00 00 55 5E B1 02 00 00 00 00 FF FF 28 BE 0C C9 21 FA B5 1E 5C 3E 5C 3E 00 00 E7 4F 00 00 87 5E B5 02 00 00 00 00 FF FF 28 BE 0C C9 21 FA B5 1E 5C 3E 5C 3E 00 00 E7 4F 00 00 B8 5E B9 02 00 00 00 00 FF FF 28 BE 0C C9 21 FA B5 1E 5C 3E 5C 3E 00 00 E7 4F 00 00 EA 5E BD 02 00 00 00 00 FF FF 28 BE 0C C9 21 FA B5 1E 5C 3E 5C 3E 00 00 E7 4F 00 00 1B 5F C1 02 00 00 00 00 FF FF 28 BE 0C C9 21 FA B5 1E 5C 3E 5C 3E 00 00 E7 4F 00 00 4D 5F C5 02 00 00 00 00 FF FF 28 BE
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (REN_APPLY_SETTINGS->RESULT)
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]



  • Muss das ein C++ Programm sein?

    Mit einer Sprache die mit RegEx umgehen kann wäre das schnell gemacht.
    grep sollte auch gehen.



  • Du spielst auf Python an oder???



  • djnforce schrieb:

    Du spielst auf Python an oder???

    Nein.
    So ziemlich jede Scriptsprache kann das (mehr oder weniger gut).
    Das einfachste ist wohl die Gnu-Version von grep.


  • Mod

    Das klingt nach einer Aufgabe, wo man mit grep, awk & Co. in 5 Minuten eine Lösung hätte (30 Minuten, wenn man sie das allererste Mal benutzt), mit Sprachen wie C oder C++ aber ziemlich lange beschäftigt wäre (und am Ende grep nachprogrammiert hätte). Das geeignete Werkzeug für die Aufgabe wählen. Nicht den goldenen Hammer nutzen.

    edit: Da bin ich wohl viel zu spät mit dem grep-Tipp. Zu viele Tabs offen...



  • komplizierte Datei 😃

    Hier mal eine C++ Lösung:

    #include <fstream>
    #include <string>
    using namespace std;
    
    int main()
    {
    	ifstream file( "test.txt" );
    
    	if( !file.is_open() ) // Konnte die Datei geöffnet werden?
    		return -1;
    
    	ofstream new_file( "neu.txt" ); // In dieser Datei wollen wir die Zahlen abspeichern.
    	new_file.setf(ios::fixed); // Keine wissenschaftliche Ausgabe.
    
    	const string what = "Coord:("; // Das suchen wir.
    	string str; // Brauchen wir, um zu testen, wann die beiden Zahlen kommen.
    
    	for(char c; file.get(c);) // Pro Schleifendurchgang lesen wir 1 Zeichen aus der Datei.
    	{
    		str += c; // Das gelesene Zeichen hängen wir an unseren string an.
    
    		if( str == what ) // Wenn im string nun "Coord:(" steht, kommen nun die beiden Zahlen.
    		{
    			double x;
    			file >> x; // Wir lesen die erste Zahl.
    
    			file.ignore( 1 ); // Das Komma interessiert uns nicht, darum ignorieren wir es.
    
    			double y;
    			file >> y; // Wir lesen die zweite Zahl.
    
    			if( file ) // Bevor wir die beiden Zahlen in die neue Datei schreiben, müssen wir vorher natürlich prüfen, ob das Einlesen der Zahlen überhaupt erfolgreich war.
    			{
    				new_file << x << ',' << y << '\n'; // Einlesen war erfolgreich. Beide Zahlen abspeichern.
    			}
    
    			str.clear(); // Wir haben zwei Coords gefunden. Nun fängt das Ganze wieder von vorne an.
    		}
    		else if( str.length() == what.length() )
    		{
    			// Wir wollen max. 7 Zeichen im string.
    			// Für den nächsten Schleifendruchgang löschen wir darum das erste Zeichen des strings, damit es nicht 8 Zeichen werden.
    			str.erase( 0, 1 );
    		}
    	}
    
    	// return 0; // ==> Wird in der main (nur in der main) automatisch gemacht. MUsst du also nicht extra hinschreiben.
    }
    


  • Wow, hast du das jetzt in den letzten 30 min gemacht? ich bin begeistert. Werde es nach dem Mittag gleich testen und mich wieder melden...



  • djnforce schrieb:

    Wow, hast du das jetzt in den letzten 30 min gemacht? ich bin begeistert. Werde es nach dem Mittag gleich testen und mich wieder melden...

    Ne, so lange hab ich jetzt nicht gebraucht. Naja der Ansatz ist ziemlich einfach. Zeichen für Zeichen lesen. Zeichen hinten an string anhängen. Zeichen ganz vorne löschen. Dann zwei Zahlen auslesen und abspeichern.
    Naja und das Kommentieren dauert immer am Längsten. 😞



  • Solche Sachen gehen auch in purem C und meist sehr viel kürzer:

    int main()
    {
      unsigned long a,b;
      FILE *f=fopen("test.txt","r");
      int c;
      while( (c=fgetc(f))!=EOF )
        if( c=='C' && 2==fscanf(f,"oord:(%lu,%lu",&a,&b) )
           printf("%lu,%lu",a,b);
      fclose(f);
      return 0;
    }
    


  • Hallo out,

    vielen vielen Dank. es funktioniert wie es soll. Nur noch zwei Fragen: Wie kann ich dass Komma nach den ersten beiden Ziffern einfügen und wie kann ich die Anzahl der Ziffern in x und y variieren?

    Also: 33.73055528,51.5242529

    Vielen Dank nochmals


  • Mod

    Welche mathematische Operation fällt dir denn ein, mit der man sowohl von 5763723838 auf 57.63723838 kommt, als auch von 2126388 auf 21.26388? Tipp: Die Antwort beinhaltet eine der folgenden Operationen: /*-+



  • natürlich 🙂



  • Hallo liebe Community,

    ich habe mal wieder ein Problem. Eure Hilfe von gestern war echt super und hat mir sehr geholfen. Jetzt habe ich aber eine neue Textdatei in welche neben den Koordinaten auch Feldstärken stehen. Aus dieser Datei soll nun eine neue Datei generiert werden, welche folgenden Inhalt haben soll x-Wert, y-Wert, Value, wobei Value die Feldstärke sein soll. Ich habe euren Code von gestern nun versucht zu erweitern und bekomme es einfach nicht hin. Was mache ich falsch??

    #include <fstream>
    #include <string>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ifstream file( "test.txt" );
    
        if( !file.is_open() ) // Konnte die Datei geöffnet werden?
            return -1;
    
        ofstream new_file( "neu.txt" ); // In dieser Datei wollen wir die Zahlen abspeichern.
        new_file.setf(ios::fixed); // Keine wissenschaftliche Ausgabe.
    
        const string what = "Coord:("; // Das suchen wir.
    	const string what2 = "Fieldstrength         : "; // Das suchen wir auch.
    
        string str; // Brauchen wir, um zu testen, wann die beiden Zahlen kommen.
    	string	str2; // brauchen wir, um zu testen, wann die Feldstärke kommt.
    
        for(char c; file.get(c);) // Pro Schleifendurchgang lesen wir 1 Zeichen aus der Datei.
        {
            str += c; // Das gelesene Zeichen hängen wir an unseren string an.
    		//cout << str2 << endl;
    		//system("pause");
            if( str == what ) // Wenn im string nun "Coord:(" steht, kommen nun die beiden Zahlen.
            {
                double x;
    			double value = 1;
                file >> x; // Wir lesen die erste Zahl.
    
                file.ignore( 1 ); // Das Komma interessiert uns nicht, darum ignorieren wir es.
    
    			double y;
                file >> y; // Wir lesen die zweite Zahl.
    
                if( file ) // Bevor wir die beiden Zahlen in die neue Datei schreiben, müssen wir vorher natürlich prüfen, ob das Einlesen der Zahlen überhaupt erfolgreich war.
                {
                    new_file << x/100000000 << ',' << y/10000000 << ',' << value << '\n'; // Einlesen war erfolgreich. Beide Zahlen abspeichern.
                }
    
                str.clear(); // Wir haben zwei Coords gefunden. Nun fängt das Ganze wieder von vorne an.
            }
            else if( str.length() == what.length())
            {
                // Wir wollen max. 7 Zeichen im string.
                // Für den nächsten Schleifendruchgang löschen wir darum das erste Zeichen des strings, damit es nicht 8 Zeichen werden.
                str.erase( 0, 1 );
            }
        }
    
    // ab hier neu
        for(char c; file.get(c);) // Pro Schleifendurchgang lesen wir 1 Zeichen aus der Datei.
        {
            str2 += c; // Das gelesene Zeichen hängen wir an unseren string an.
            if( str2 == what2 ) // Wenn im string nun "Coord:(" steht, kommen nun die beiden Zahlen.
            {
    			double value; // Feldstärke
                file >> value; // Feldstärke einlesen
    
                if( file ) 
                {
                    new_file << value << '\n'; // Einlesen war erfolgreich. Feldstärke abspeichern.
                }
    
                str2.clear(); // Nun fängt das Ganze wieder von vorne an.
            }
            else if( str2.length() == what2.length())
            {
                // Wir wollen max. 7 Zeichen im string.
                // Für den nächsten Schleifendruchgang löschen wir darum das erste Zeichen des strings, damit es nicht 8 Zeichen werden.
                str2.erase( 0, 1 );
            }
        }
        // return 0; // ==> Wird in der main (nur in der main) automatisch gemacht. MUsst du also nicht extra hinschreiben.
    }
    

    Hier auch noch ein Auszug aus der Textdatei:

    => ATStationTmcInfo : enATStationTmcInfo_Station_is_TMC_station (0x02)
    => Fieldstrength : 56 dB/uV
    => u8Quality : 00
    => Band : enBand_FM (0x00)
    => ActivePresetList : 0f20
    => PresetAutocompare : 0000
    => StationListAutocompare: 0000
    => ATStationInfo : 06
    [tun_DrvAdrIf.hpp(1792)]
    proxyfile@cardTrace Class : TUN_TRACE_CLASS_DRVADRIF Trace Level : TR_LEVEL_USER_1[STATE_TRANSITION]
    proxyfile@card(core2)fc_tmctuner_US1_ETG_TUN_TRACE_CLASS_DRVADRIF: tun_DrvAdrIf::vFreeRxDataBuffer() -> release Rx SSI buffer [tun_DrvAdrIf.cpp(541)]
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_DEAD_RECKONING_POSITION->STATUS) State: VALID, Time: 37278, Posix: 37s+628ms, Pos: (-921911768,515242529) (Err:406,163,1), Head: 258 (Err:5098), Turnrate: 1 (Err:9), Speed:0 (Err:270), Accel: 0 (Err:249), Height: 0 (Err:2), Sensors: prov:15, det:6, used:6, cal:0
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_POSITION->STATUS) WGS84: (-921911785,515242200), Reliab: 0x001E, Speed: 0 cm/s, Head: 0xFE, ON_ROAD, Time: 37.628, Inclination: 0, Acceleration: 0 cm/s^2, Height: (0,) m
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_EXTRAPOLATED_POSITIONS->STATUS) Dataset:235575863 RelID:1 Rel:80 Time:38,698 Int:40 NumPts:50: Coord:(3373055528,515242529) Head:16456 Angl:16456 Speed:0 7F 54 00 00 78 24 1B 01 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 12 55 00 00 81 24 32 01 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 12 55 00 00 C0 24 42 01 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 12 55 00 00 FF 24 51 01 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 12 55 00 00 3E 25 5F 01 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 12 55 00 00 7C 25 6D 01 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 12 55 00 00 BA 25 7A 01 00 55 00 00 00 00 28 BE
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_DEAD_RECKONING_POSITION->STATUS) State: VALID, Time: 38278, Posix: 38s+628ms, Pos: (-921911768,515242529) (Err:406,164,1), Head: 231 (Err:5098), Turnrate: 0 (Err:0), Speed:0 (Err:0), Accel: 0 (Err:0), Height: 0 (Err:2), Sensors: prov:15, det:6, used:6, cal:0
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_POSITION->STATUS) WGS84: (-921911785,515242200), Reliab: 0x001E, Speed: 0 cm/s, Head: 0xFE, ON_ROAD, Time: 38.628, Inclination: 0, Acceleration: 0 cm/s^2, Height: (0,) m
    proxyfile@cardTrace Class : TR_ENAVI_RECV_DATA Trace Level : TR_LEVEL_SYSTEM[ERROR]
    proxyfile@card(core0)ENAVI_RX: (POS_EXTRAPOLATED_POSITIONS->STATUS) Dataset:235575863 RelID:1 Rel:80 Time:39,708 Int:40 NumPts:50: Coord:(3373055528,515242529) Head:16456 Angl:16456 Speed:0 12 55 00 00 81 24 32 01 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 16 55 00 00 81 24 38 00 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 16 55 00 00 C0 24 4F 00 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 16 55 00 00 FF 24 61 00 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 16 55 00 00 3E 25 70 00 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 16 55 00 00 7C 25 7D 00 00 55 00 00 00 00 28 BE 0C C9 21 FA B5 1E 48 40 48 40 00 00 16 55 00 00 BA 25 89 00 00 55 00 00 00 00 28 BE
    proxyfile@cardTrace Class : TUN_TRACE_CLASS_DRVADRIF Trace Level : TR_LEVEL_USER_2[EVENT]

    Vielen Dank schonmal und viele Grüße...



  • Was ist denn das Problem?


  • Mod

    Nichts gegen C++, aber das kann man ja nicht mit ansehen, wie du solch einen Aufwand für solch eine triviale Aufgabe betreibst. Hier, fünf Zeilen Shellscript machen alles, was du willst:

    FS=`grep -o -m1 "Fieldstrength : [0-9]*" $1 | cut -d' ' -f3`
    XY_STRING=`grep -o -m1 "Coord:([0-9]*,[0-9]*)" $1`
    X=`echo $XY_STRING | cut -d'(' -f2 | cut -d',' -f1`
    Y=`echo $XY_STRING | cut -d',' -f2 | cut -d')' -f1`
    echo $X, $Y, $FS
    

    Kurz, (relativ) einfach, erweiterbar. Jemand, der sich besser mit Regex auskennt kann sicherlich auch noch zaubern, dass man gleich den gewünschten Wert erhält, ohne die anschließende cut-Orgie. Aber auch mit meinen Laienkenntnissen ist dies doch schon sehr viel besser als das was du derzeit versuchst.

    Diese Version nutzt Unix-Kommandozeilentools. Gibt sicher auch vergleichbar mächtiges für Windows, falls nötig. Zur Not gibt es diese Tools natürlich auch alle direkt für Windows.



  • So wie der Code oben abgebildet ist, wird garnicht in die zweite for-Schleife gegangen. Die Koordinaten werden mithilfe der ersten for-Schleife ausgelesen und sauber in die neue Textdatei geschrieben (Mit einem fiktiven Value Wert von 1).

    Ich glaub ich seh den Wald vor Bäumen nicht. So schwer kann das doch nicht sein oder?



  • Hier, fünf Zeilen Shellscript machen alles, was du willst

    Ich habe jetzt aber mit c++ begonnen und würde es auch gern damit beenden. Viel fehlt ja nichtmehr. Ausserdem erhoffe ich mir dadurch Lerneffekte für zukünftige Projekte.



  • djnforce schrieb:

    Hier, fünf Zeilen Shellscript machen alles, was du willst

    Ich habe jetzt aber mit c++ begonnen und würde es auch gern damit beenden. Viel fehlt ja nichtmehr. Ausserdem erhoffe ich mir dadurch Lerneffekte für zukünftige Projekte.

    Mir fällt keine gute Lösung ein. 😞 Da musst do wohl auf getline + stringstream zerhacke zurückgreifen. 😃



  • Ich wähnte mich schon am Ziel, als ich las, dass man mit ignore() auch alles ignorieren kann bis zu einem definierten Character. Also bis "Fieldstrength" erscheint. Aber das geht wohl nur mit einem Zeichen und nicht mit einem ganzen Wort. Hab ich das richtig verstanden?


Anmelden zum Antworten