bestimmte Zeilen in Array speichern und wieder ausgeben



  • Hallo zusammen,

    da mir hier immer wieder schnell und gut geholfen wird, versuche ich es auch bei diesem Problem wieder hier...

    Ich habe folgende Textdatei:

    KI OH ZGZH3 HUNDANF;
    OK=3 
    GH=5
    GH=0 XY=15
    HUNDENDE;
    KO=2
    INFO("TEST")
    KO VT FTR KATZEANF:
    GI=7
    OK=5
    N3 KATZEENDE;
    IK=3;
    REPEAT HUNDANF; HUNDENDE;
    KO=2
    REPEAT KATZEANF; KATZEENDE;
    

    Die Zeilen zwischen HUNDANF; und HUNDEND;(Zeile 2-4), sollen bei der Anweisung

    REPEAT HUNDANF; HUNDENDE;
    

    nochmals ausgegeben werden. Egal wo...

    Genau dasselbe soll aber auch bei weiteren REPEATS geschehen.
    Siehe KATZEANF; und KATZEENDE; (Zeile 9 und 10);

    Wie kann man sowas am Besten realisieren?
    Ich müsste ja beim Einlesen der Zeilen, auftretende ANF; und ENDE; suchen und
    den Text davor mitspeichern. Wenn ein ANF; gefunden wurde, müssen die Zeilen
    bis zu dem END; gespeichert werden. Und wie fange ich das mit dem REPEAT ab?



  • So den richtigen Zusammenhang kann ich in deiner Textdatei zwar nicht erkennen, ich würde eher sowas wie REPEAT HUND erwarten, aber das ist ja egal. Mir scheint es so, als das alle Befehle durch ein Leerzeichen getrennt sind? Dann würde ich die Anweisungen separieren und für jede schauen ob der Bezeichner mit ANF endet. Falls ja merke ich mir die Bezeichnung (zB HUND) und suche den Befehl HUNDENDE. Somit habe ich alle Befehle ermittelt, die dann später REPEAT HUND substituieren sollen. Diese Befehlskette brauche ich mir also nur noch als HUND merken.



  • Die Maschine muss wissen von wo bis wo Sie wiederholen soll.
    Deswegen:

    REPEAT HUNDANF; HUNDENDE;
    

    Genau, es ist alles durch ein Leerzeichen getrennt.

    Ich würde auch zuerst nach einem ANF; suchen:

    if( strstr(Zeile,"ANF;") 
    {
    
    }
    

    wie kann ich aber von der gefundenen Position rückwärts, nach dem
    ersten Leerzeichen suchen ?

    Also aus :

    KI OH ZGZH3 HUNDANF;
    

    soll das hier werden:

    HUNDANF;
    

    Und dieser char muss gespeichert werden, um ihn bei einem späteren REPEAT zu
    vergleichen...



  • Benji2010 schrieb:

    Die Maschine muss wissen von wo bis wo Sie wiederholen soll.
    Deswegen:

    REPEAT HUNDANF; HUNDENDE;
    

    Wenn die Maschine weiß, dass sie HUND wiederholen soll, dann reicht das doch. Oder warum muss sie wissen, dass HUND einen Anfang und ein Ende hat? Das kann man einfach voraussetzen.

    Benji2010 schrieb:

    wie kann ich aber von der gefundenen Position rückwärts, nach dem
    ersten Leerzeichen suchen ?

    Du verstehst das falsch. Nicht den ganzen Text als String betrachten, sondern nur die einzelnen Befehle. Dann reicht es aus, zu wissen an welcher Position der Befehl steht.
    Um mich auf dein Eingangsbeispiel zu beziehen. HUNDANF ist Befehl 4, HUNDENDE Befehl 9. Also merkst du dir Befehl 5 bis 8 ist die Befehlskette mit Namen HUND. Wenn der Befehl nun REPEAT heißt holst du dir den Namen noch dahinter und suchst ihn aus einer Liste, wo du alle Befehlsketten gespeichert hast.



  • Danke für die schnelle Antwort...
    Leider kann ich dies nicht nur einzeln betrachten, sondern eine Zeile muss gesamt betrachtet werden. Das restliche Programm ist so aufgebaut und es würde Abweichungen geben. Es ist ein Unterschied ob X=0 in der ersten Zeile steht und Y=250 in der zweiten, oder ob beide in einer Zeile stehen. Ich gebe mal ein richtiges Beispiel an, dass vorige sollte eigentlich der Einfachheit dienen.

    So sieht die Textdatei aus:

    N90 Z9
    N100 SAUGANF:
    N110 MSG("SAUGSEITE")
    N120 G1 X275
    N130 Y230
    N140 X380
    N150 Y-70
    N160 X295
    N170 Y-280
    N180 X150 Y-400
    N190 G0 Z=IC(20)
    N200 X-340 Y620
    N210 Z=IC(-20)
    N220 SAUGEND:
    N230 Z9
    N240 DRUCKANF:
    N250 MSG("DRUCKSEITE")
    N260 G1 X-290
    N270 Y-450
    N280 G0 Z=IC(20)
    N290 X370 Y620
    N300 Z=IC(-20)
    N310 DRUCKEND:
    N320 Z6
    N330 REPEAT SAUGANF SAUGEND
    N340 Z6
    N350 REPEAT DRUCKANF DRUCKEND
    N360 Z3
    N370 REPEAT SAUGANF SAUGEND
    N380 Z3
    

    Ich möchte jetzt eigentlich "nur" das wenn er ein ANF: im Satz findet, ohne REPEAT in der Zeile, dass er diesen Wert speichert:

    SAUGANF
    

    also in etwa so:

    if( strstr(Zeile,"ANF:"))
      {  
         if(strstr(Zeile,"REPEAT"))
         {
         }else
         { 
           Speicher den Wert vom Leerzeichen bis zum ':' --> "SAUGANF"
           Wie man diesen Wert speichern kann, weiß ich jetzt leider nicht.
           a = 1;
         }
    
    [cpp]if( strstr(Zeile,"END:"))
    {
      a=0;
    }
    
    if ( a=1 )
    {
       speicher die Zeilen, um sie später nochmals auzugeben...
    }
    
      }
    

    Und wenn er ein REPEAT in der Zeile findet, soll er den char dahinter mit den gespeicherten vergleichen, umd die Zeilen dazwischen nochmals auzugeben :

    if(strstr(Zeile,"REPEAT"))
         {
            strcmp oder ähnlich
         }
    

    Hoffe es ist ein wenig verständlicher geworden.Leider ist dieses Problem ein wenig komplex. 😞



  • Benji2010 schrieb:

    Leider kann ich dies nicht nur einzeln betrachten, sondern eine Zeile muss gesamt betrachtet werden.

    Das sollte ja nicht das Problem sein, ob nun Leerzeichen oder Zeilenumbruch.

    Benji2010 schrieb:

    Speicher den Wert vom Leerzeichen bis zum ':' --> "SAUGANF"
    Wie man diesen Wert speichern kann, weiß ich jetzt leider nicht.

    Zurück gehen bis zum Wortanfang? Wenn du clever bist merkst du dir noch die Postion von ANF und kannst mit einem festen Offset die gesamte Stringlänge bestimmen.

    Benji2010 schrieb:

    speicher die Zeilen, um sie später nochmals auzugeben...

    Sollte ja nicht das Problem sein?

    Was ich aber immer noch nicht verstanden habe, warum der REPEAT-Aufruf so umständlich sein muss?

    Benji2010 schrieb:

    if(strstr(Zeile,"REPEAT"))
         {
            strcmp oder ähnlich
         }
    

    Du solltest lieber in der Zeile mit REPEAT nach HUNDANF suchen.

    Benji2010 schrieb:

    Hoffe es ist ein wenig verständlicher geworden.Leider ist dieses Problem ein wenig komplex. 😞

    Ich denke C ist auch nicht die geeignete Sprache um einen Parser zu schreiben. In anderen Sprachen könntest du dir einfach deine Regeln definieren, damit wird die Sache wesentlich entspannter. Zum Beispiel in Perl hast du immer noch eine C ähnliche Syntax. Für dein Problem wird wohl Yacc, die richtige Wahl sein.



  • Steht die Textdatei nur auf der Platte oder wird die gesammte Datei in den Speicher geladen?

    Jedenfalls musst du dir die Positionen der Zeilen merken. Am sinnvollsten in einer struct.
    Z.B.:

    struct repeat { char label[32];
                    char  *anfang, *ende;  // im Speicher
    /* oder */    size_t   anf, end;       // in Datei
                  }
    

    Davon eine verkettete Liste (am Anfang reicht ein Array).

    Ist der ':' bei SAUGANF: zwingend und kann der auch beim REPEAT angegeben werden?

    Wenn der : nur im Label steht brauchst du nicht mehr nachschauen ob noch ein REPEAT in der Zeile ist wenn du "ANF:" und "END:" gefunden hast.



  • @ Nick unbekannt
    Leider ist das komplette Programm bereits in C++ geschrieben worden. Ich bin nun derjenige der ein paar Sachen umstricken muss. Leider ist der Zeitaufwand zu hoch, dass gesamte Programm umzustellen/umzuschreiben.

    @DirkB
    die Datei liegt auf der Platte und es wird jede Zeile nach und nach eingelesen.

    int CCbfk::PreProcessNcFile( char *FileName, char *PreFileName )
    {
        FILE * fpIn, * fpOut;
        char Zeile[300], c[20], *z;
        int     a;  // Parameter-Start:     normal 1, bei HOLES2 40 (zum Schutz der P1..)
        int     n;  // Parameter-Zähler:    normal 1.., bei HOLES2 40..
    
        if (( fpIn = fopen( FileName, "rt" )) == NULL )
            return 0;
        if (( fpOut = fopen( PreFileName, "wt" )) == NULL )
        {
            fclose( fpIn );
            return 0;
        }
        while (( fgets( Zeile, 200, fpIn )) != NULL )
        {
            a = 1;                                          // normale Parameter-Liste P1 ...
            Replace( Zeile, "CYCLE", "L" );
            Replace( Zeile, "LONGHOLE", "L1001" );
            Replace( Zeile, "SLOT2", "L1002" );
    		Replace( Zeile, "ROTH", "L892" );				// Ersetzen des ROTH-Befehls durch L892
    		Replace( Zeile, "T_NR", "U1");					// Ersetzen des Unterprogrammes T_NR durch U1
    		if ( Replace( Zeile, "C=DC", "D893" ))			 //Ersetzen der Drehung des Tisches auf C=
    			while ( Replace( Zeile, ")", "" ));
    		if ( Replace( Zeile, "C=IC", "D894" ))			// Ersetzen der inkrementalen Drehung auf CI=
    			while ( Replace( Zeile, ")", "" ));
    		if ( Replace( Zeile, "X=IC", "D895" ))			// Ersetzen der inkrementalen Zustellung X auf XI=
    			while ( Replace( Zeile, ")", "" ));
    		if ( Replace( Zeile, "Y=IC", "D896" ))			// Ersetzen der inkrementalen Zustellung Y auf YI=
    			while ( Replace( Zeile, ")", "" ));
    		if ( Replace( Zeile, "Z=IC", "D897" ))			// Ersetzen der inkrementalen Zustellung Z auf ZI=
    			while ( Replace( Zeile, ")", "" ));
    		if ( Replace( Zeile, "HOLES2", "L1003" ))
            {
                a = 40;                                     // geschützte Parameter-Liste P40 ...
            }
    
            if (( z = strstr( Zeile, "SPOS" )) != NULL )
                strcpy( z, "M19\n" );   // abschneiden nach M19
    			Replace( Zeile, "MCALL", "M100" );
            if (( z = strchr( Zeile, '(' )) != NULL )   // Beginn Parameterliste gefunden
            {                                           // Zeile=N470 M100   L81(5,0,2,-81, ,2)
                                                        // z=(5,0,2,-81, ,2)
                while ( Replace( z, " ", "" ));         // z=(5,0,2,-81,,2)
                while ( Replace( z, ",,", ",0," ));     // z=(5,0,2,-81,0,2)
                n = a;                                  // Zähler mit Startwert init (1 oder 40)
    
                sprintf( c, " R%d=", n++ );             // c= R1=
                Replace( Zeile, "(", c );               // Zeile=N470 M100   L81 R1=5,0,2,-81)
                do
                    sprintf( c, " R%d=", n++ );             // c= R2=
                while ( Replace( Zeile, ",", c ));      // Zeile=N470 M100   L81 R1=5 R2=0,2,-81)
                                                        // Zeile=N470 M100   L81 R1=5 R2=0 R3=2,-81)
                                                        // Zeile=N470 M100   L81 R1=5 R2=0 R3=2 R3=-81)
            }
    	    Replace( Zeile, "MCIRCLE", "M889" );
    		Replace( Zeile, "MPOINT", "M888" );
    		Replace( Zeile, "MDIA", "M890" );
    
    		if (( z = strchr( Zeile, ';' )) != NULL )   // Kommentar beginnt mit ';' 
                *z = '(';
            fprintf( fpOut, "%s", Zeile );
        }
        fclose( fpIn );
        fclose( fpOut );
        return 1;
    }
    

    Ist der ':' bei SAUGANF: zwingend und kann der auch beim REPEAT angegeben werden?

    Ja der ist zwingend und in der Repeatzeile darf dieser nicht vorkommen.

    Wenn der : nur im Label steht brauchst du nicht mehr nachschauen ob noch ein REPEAT in der Zeile ist wenn du "ANF:" und "END:" gefunden hast.

    Stimmt, das ist ein guter Hinweis...

    Die Idee mit der struct klingt interessant, nur wie soll ich mir die Positionen der Zeilen merken bzw. verketten?



  • Benji2010 schrieb:

    @ Nick unbekannt
    Leider ist das komplette Programm bereits in C++ geschrieben worden. Ich bin nun derjenige der ein paar Sachen umstricken muss. Leider ist der Zeitaufwand zu hoch, dass gesamte Programm umzustellen/umzuschreiben.

    Das ist C++? Warum postest du dann ins C-Forum? Unter C++ ist das doch alles ganz einfach. Du liest deine Zeile in einen String, schaust nach ob ANF ohne REPEAT in der Zeile steht, dann merkst du dir den Namen zum Beispiel HUND. Danach speicherst du alle folgenden Zeilen in einen extra String, bis du ENDE findest. Das ganze kommst dann in eine Map[HUND] = befehlsstring. Und wenn du die Zeile REPEAT HUNDANF HUNDENDE findest, extrahierst du wieder den Bezeichner und holst dir aus der Map den Befehlsstring.
    Das alles kannst du mit String und Map einfach realisieren, ohne dich mit Zeigern oder sonstigen C-Fallen rum ärgern zu müssen.
    Und die Methode ist auch nicht so umfangreich, dass du sie nicht auch komplett von C auf C++ umstellen kannst.



  • die Datei liegt auf der Platte und es wird jede Zeile nach und nach eingelesen.

    Es gibt die Funktionen ftell und fseek.

    Die liefern dir /setzen die aktuelle Lese/Schreibposition in einer Datei.

    Möglicherweise geht es so:
    Du merkst dir die aktuelle Position und liest eine Zeile ein
    Ist "ANF:" drin Label und gemerkte Position in struct.anf
    Ist "END:" drin aktuelle Position in struct.end

    "REPEAT" gefunden: aktuelle FilePosition merken, Label in struct suchen
    fseek auf struct.anf und (end-anf) Zeichen kopieren.
    fseek auf gemerkte Position von REPEAT

    PS: Du darfst eine Datei auch mehrmals zum lesen öffnen. Aus dem ersten fopen liest du deine Anweisungen und ftell; in der zweiten kannst du dann mit fseek hin- und herspringen und die Schleifen auslesen.



  • Was du brauchst ist ein kleiner Interpreter, der auf einem zuvor aus der Datei eingelesenen Stringarray arbeitet. Den ganzen Dateikram brauchst du nicht, du läufst dann alle Zeilen durch und falls du auf eine Aktionszeile triffst, führst du mit den Parametern aus dieser Zeile, dem gesamten Stringarray und deinen sonstigen Notwendigkeiten eine vorbereitete Funktion aus.
    Das alles ist äußerst trivial und in wenigen Zeilen zu erledigen.



  • Danke für die vielen Hinweise !

    Ich werde jetzt erstmal die Vorschläge durcharbeiten und mal einen Quellcode-Vorschlag erstellen...Für mich ist dies jedoch nicht so trivial... 🙄


Log in to reply