Ersetzen von Tabulator durch Leerzeichen



  • Djangou schrieb:

    Doch, es funktioniert soweit

    Wie kann das sein, wenn ich es nicht mal kompiliert bekomme?

    In Funktion »main«:
    21:22: Fehler: Anfrage nach Element »good« in etwas, was keine Struktur oder Variante ist
    

    Sag mir, wie du das kompiliert bekommen hast, ja?

    Djangou schrieb:

    Wie kann ich denn prüfen, ob die Datei gelesen wurde

    Prüfung auf (void*)0 (auch bekannt als NULL ) sollte reichen.

    Djangou schrieb:

    nur halt mit dem argv[1] konnte ich das noch nicht testen.

    Allein vom Code kann ich ja schon sehen, dass das so nicht funktionieren KANN. '\t' ist eine Escape-Sequenz, die besteht aus einem Byte:

    $ perl -e 'printf("\t");' | hd
    00000000  09                                                |.|
    00000001
    

    Ein Byte: 0x09. Du versuchst aber zwei Bytes einzulesen und zu interpretieren. Entweder hast du nicht getestet oder du lügst uns an.



  • dachschaden schrieb:

    Entweder hast du nicht getestet oder du lügst uns an.

    Das kann man aber auch etwas freundlicher sagen, Herr dachschaden.



  • SeppJ schrieb:

    *: Der Standard (K.3.5.4.1, 6) empfiehlt aber ausdrücklich, fgets zu benutzen! Bin fast vom Stuhl gefallen, als ich gelesen habe, dass der Standard sich so weit vor wagt, konkrete Empfehlungen zu machen!

    Die Implementierung von gets_s (und dem ganzen anderen _s-Krempel) ist doch optional, oder? Von daher ist die Empfehlung doch durchaus nachvollziehbar, auch wenn sie im Rahmen eines solchen Dokuments abgegeben wird.



  • @dachschade
    oder du hast nicht richtig gelesen ...
    Ich habe oben geschrieben, das ich das mit dem good entfernt habe.

    Also muss man das mit dem char_ = fgetc(fP);
    durch if(char_ = fgetc(fP) != NULL)
    ersetzen?

    Ich habe auch ein Beispiel gekriegt und die Ausgabe sieht bei mir genau so aus, also so:

    Eingabe
    567\tabc
    234567\tabc
    23456789\tabc
    123456789012345\tabc

    Ausgabe
    567 abc
    234567 abc
    23456789 abc
    123456789012345 abc

    Also läuft das ganze doch richtig?

    @EOP
    Danke aber ich brauche niemanden der mich hier beschützt. Letztendlich ist es ja sowieso "unpersönlich" und daraus mache ich mir dann eh nicht viel. 😉
    Allerdings weiß man ja auch nie, wie das ganze wirklich gemeint ist.



  • Ich habe mal die Ausgabe in Code-Tags gesetzt. Da bleiben die Leerzeichen und Tabulatoren erhalten.

    Djangou schrieb:

    Ich habe auch ein Beispiel gekriegt und die Ausgabe sieht bei mir genau so aus, also so:

    Eingabe
    567\tabc
    234567\tabc
    23456789\tabc
    123456789012345\tabc

    Ausgabe

    567	abc
    234567	abc
    23456789	abc
    123456789012345	abc
    

    Also läuft das ganze doch richtig?

    In der Ausgabe sind Tabulatoren (zwischen den Ziffern und den Buchstaben).

    In deinem ersten Post hieß es noch:

    Aufgabe für Djangou schrieb:

    Dabei ist aber jeder Tabulator (in C dargestellt durch '\t') in die entsprechende Anzahl Leerzeichen umzuwandeln.

    Wo sind also die Leerzeichen? Da sind Tabulatoren drin.

    Deine Aufgabe ist es, das was du da als Ausgabe hast in einen Text ohne Tabulatoren zu wandeln, der aber genauso aussieht.

    \t ist eine Escapesequenz (aus zwei Zeichen). Diese wird vom Compiler in das eine Steuerzeichen mit dem Wert 9 umgewandelt. DArum geht es hier aber nicht.
    Du sollst das ZEichen mit dem Wert 9 in eine Anzahl Leerzeichen umwandeln.

    Öffne mal den Editor von Windows (notepad.exe) und gib den Text (Eingabe von oben) ein
    Statt \t drückst du die Tabulatortaste (links neben Q). Abspeichern nicht vergessen.
    Du kannst jetzt den Zwischenraum bei den Tabulatoren nur als ganzes auswählen.
    In der Ausgabe sollen da stattdessen Leerzeichen stehen. Da kannst du dann jedes Leerzeichen einzeln auswählen.



  • Hmm ... stimmt.
    
    Wie kann man das denn am besten machen?
    Ich hatte jetzt einmal versucht die Zeichen zu zählen und demnach zu reagieren aber das funktioniert aber leider nicht so ganz.
    
    So sieht das ganze derzeit aus: (Ich habe mal die main weggelassen, weil sich ja nichts geändert hat)
    
    void expand(FILE *filePointer)
    {
    	int i = 0;
    	int counter = 0;
    	int character = 0;
    
    	if(filePointer != NULL) 
    	{	
    		while((character = fgetc(filePointer)) != EOF)
            {        
    			counter++;	
    
    			if(counter >= 8)	
    				counter = 0;
    
            	if(character == '\\') // oder char = 92
    			{ 			
    				counter--;
    				character = fgetc(filePointer);
    				counter++;
    
    				if(counter >= 8)	
    					counter = 0;
    
    				if(character == 't') // oder char == 116
    				{ 					
    					counter--;
    
    					if(counter >= 8)	
    						counter = 0;
    
    					switch(counter)
    					{
    						case 0:
    							i = 8;
    							break;
    						case 1:
    							i = 7;
    							break;
    						case 2: 
    							i = 6;
    							break;
    						case 3: 
    							i = 5;
    							break;
    						case 4:
    							i = 4;
    							break;
    						case 5: 
    							i = 3;
    							break;
    						case 6: 
    							i = 2;
    							break;
    						case 7: 
    							i = 9;
    							break;
    					}
    
    					while(i != 1)
    					{
    						// printf("%d   ", counter);
    						putchar(32);
    						printf("%d", i);
    						i--;
    					}
    						//putchar(32); printf("\t");
    				}
    				else if(character == 'n')
    				{
    					counter = 0;
    				}
    				else 
    				{
    					putchar(92); // entspricht einem \
    					putchar(character);
    				}		
    			}
    			else 
    				putchar(character); // Die Zeichen ausgeben
    		}
    	}
    	else 
    		printf("Die Datei existiert nicht oder Sie konnte nicht geöffnet werden!");
    }
    
    567	abc
    234567	abc
    23456789	abc
    123456789012345	abc
    


  • So soll das ganze nachher aussehen:

    http://i.imgur.com/wnVMwDi.png



  • In deiner Eingabedatei (wenn sie richtig ist), kommt weder das Zeichen \ noch t noch n drin vor.
    Also sind deine Vergleiche (Zeile 24, 34 und 78) nicht richtig.
    (Komischerweise war der Vergelich in deinem ersten Post richtig.)

    Sehrwohl kommen der Tabulator und und Newline drin vor.

    Und bei deinem switch gibt es einen Zusammenhang zwischen counter, i und der Zahl mit der du counter immer vergleichst.
    Diesen Zusammenhang kann man mit einer Subtraktion ausdrücken.

    Komischerweise war der Vergelich in deinem ersten Post richtig



  • @EOP: Könnte ich. Aber warum sollte ich?

    @OP: Schau dir mal diese kleine Referenzimplementierung an:

    #include <limits.h> /*Fuer size_t*/
    #include <string.h> /*Fuer strlen*/
    #include <stdlib.h> /*Fuer die EXIT_*-Konstanten*/
    #include <stdio.h>  /*Fuer printf und solche Spaesse.*/
    
    /*Seit mich DirkB darauf aufmerksam gemacht hat, dass %lu nicht immer korrekt
    **ist, aber da %z erst in C99 vorgestellt wurde ... :p*/
    #if defined(__x86_64__) || defined(_M_X64)
     #ifdef _WIN64
      #ifdef __CYGWIN__
       #define SIZE_T_PRINTF "%lu"
      #else
       #define SIZE_T_PRINTF "%I64u"
      #endif
     #else
      #define SIZE_T_PRINTF "%lu"
     #endif
    #else
     #define SIZE_T_PRINTF "%u"
    #endif
    
    /*Anzahl der Zeichen, die ein Tabstopp wert ist.*/
    #define SPACES_PER_TAB (4)
    
    /*Zeichen, welches das Ersetzen auslösen soll.*/
    #define SEARCH_CHAR '\t'
    
    int main(int argc,char*argv[])
    {
            size_t index_args,
                    index_string,
                    index_string_visual,
                    spaces_current,
                    spaces_left_to_print,
                    string_length;
    
            /*Keine Daten angegeben.*/
            if(argc<2)
            {
                    fprintf(stderr,"Usage: %s <parameters>\n",argv[0]);
                    exit(EXIT_FAILURE);
            }
    
            for(index_args=1;index_args<argc;index_args++)
            {
                    /*Anfang des Strings.*/
                    printf("Chunk No. " SIZE_T_PRINTF "\n"
                            "===============================================================================\n",
                            index_args);
    
                    /*Ansgabe mit gleichzeitiger Ersetzung.*/
                    string_length=strlen(argv[index_args]);
                    for(index_string=0,index_string_visual=0;index_string<string_length;index_string++,index_string_visual++)
                    {
                            if(argv[index_args][index_string]==SEARCH_CHAR)
                            {
                                    spaces_current=0;
                                    spaces_left_to_print=SPACES_PER_TAB-index_string_visual%SPACES_PER_TAB;
    
                                    while(spaces_current++<spaces_left_to_print)
                                            printf(" ");
                                    index_string_visual+=spaces_left_to_print-1;
                            }
                            else
                                    printf("%c",argv[index_args][index_string]);
                    }
    
                    /*Ende des Strings.*/
                    printf("\n\n");
            }
    
            /*Alles lief besser als erwartet.*/
            exit(EXIT_SUCCESS);
    }
    

    Ist nicht das komplette Program, funktioniert aber:

    $ perl -e 'printf("\t 131312 \t13\t\t123 12s3r12j13aj\tddsad")' | xargs -0 ./tab 
    Chunk No. 1
    ===============================================================================
         131312     13      123 12s3r12j13aj    ddsad
    

    Wenn man einen Tabsize von 8 eingibt, funzt es auch:

    $ perl -e 'printf("\t 131312 \t13\t\t123 12s3r12j13aj\tddsad")' | xargs -0 ./tab
    Chunk No. 1
    ===============================================================================
             131312         13              123 12s3r12j13aj        ddsad
    

    War aber jetzt schnell zusammengehackt. Ich übernehme also keine Garantie für Fehler.

    EDIT: Ich soll mich hinlegen, habe die Prüfung für VS-Compiler vergessen. 😕



  • dachschaden schrieb:

    /*Seit mich DirkB darauf aufmerksam gemacht hat, dass %lu nicht immer korrekt
    **ist, aber da %z erst in C99 vorgestellt wurde ... :p*/
    #ifdef __x86_64__
    #define SIZE_T_PRINTF "%lu"
    #else
    #define SIZE_T_PRINTF "%u"
    #endif
    

    Wofür soll das sein?
    Was bewirkt das?
    Warum verzichtest du auf C99?

    Warum erkärst du nicht, was dein Programm anders macht gegenüber der Aufgabenstellung?



  • DirkB schrieb:

    Warum verzichtest du auf C99?

    Diese Diskussion hatten wir bereits.

    DirkB schrieb:

    Warum erkärst du nicht, was dein Programm anders macht gegenüber der Aufgabenstellung?

    Weil der OP hier eine Teillösung bekommt und lernen soll, diese selbstständig in seine Aufgabenstellung einzubinden.



  • dachschaden schrieb:

    DirkB schrieb:

    Warum verzichtest du auf C99?

    Diese Diskussion hatten wir bereits.

    Wenn du damit eine Kompatibilität zu alten C-Compilern von Microsoft haben willst, dann funktioniert das so nicht.

    __x86_64__ ist bei Visual-Studio nicht definiert.
    long ist auch auf Windows bei 64-Bit-Programmen "nur" 32-Bit groß.
    size_t ist aber auf Windows bei 64-Bit-Programmen durchaus 64-Bit groß.

    Bei anderen Compilern als GCC bekommst du also %u. Und das ist aber auch nicht immer richtig.



  • DirkB schrieb:

    __x86_64__ ist bei Visual-Studio nicht definiert.

    Hast recht, habe noch die Prüfung auf _M_X64 eingefügt und %I64u verwendet.

    DirkB schrieb:

    long ist auch auf Windows bei 64-Bit-Programmen "nur" 32-Bit groß.
    size_t ist aber auf Windows bei 64-Bit-Programmen durchaus 64-Bit groß.

    Das weiß ich. Deswegen verwende ich auch nur size_t.



  • dachschaden schrieb:

    DirkB schrieb:

    __x86_64__ ist bei Visual-Studio nicht definiert.

    Hast recht, habe noch die Prüfung auf _M_X64 eingefügt.

    Dann ist das immer noch falsch.

    dachschaden schrieb:

    DirkB schrieb:

    long ist auch auf Windows bei 64-Bit-Programmen "nur" 32-Bit groß.
    size_t ist aber auf Windows bei 64-Bit-Programmen durchaus 64-Bit groß.

    Das weiß ich.

    Anscheinend nicht. %lu steht für unsigned long .
    Was hat das mit size_t zu tun, wenn _M_X64 definiert ist?
    Und was hat %u mit size_t in den anderen Fällen zu tun?

    dachschaden schrieb:

    Deswegen verwende ich auch nur size_t.

    Wenn man davon ausgehen kann, dass int ausreicht, dann nimmt man int ²
    Und in deinem Programm reicht int aus.



  • DirkB schrieb:

    Dann ist das immer noch falsch. [...] %lu steht für unsigned long .

    Schau dir den letzten EDIT an.


  • Mod

    size_t s;
    printf("%llu", (unsigned long long)s);
    

    ?



  • @SeppJ: Ist long long nicht wieder in C99 eingeführt worden?


  • Mod

    dachschaden schrieb:

    @SeppJ: Ist long long nicht wieder in C99 eingeführt worden?

    Dann nimmste eben unsigned long. Die Fälle, in denen selbst das nicht mehr funktioniert sind weitaus konstruierter als die Fälle, in denen deine jetzige Lösung nicht funktioniert.



  • Auf jeder Windows-Maschine kann dir das auf die Füße fallen. Weil long auf Windows 64-Bit 32 Bit groß ist, aber size_t 64 Bit. Und nicht nur bei printf , sondern auch bei sprintf , snprintf ... hat DirkB doch schon geschrieben. Wenn ich mir Objekten arbeite, die >4 GB groß sind, bekomme ich Müll.
    So ein Problem hatte ich schon mal, und es überhaupt zu finden hat mich 10 Stunden meines Lebens gekostet. Da riskiere ich lieber eine Warnung vom Compiler und eine nachträgliche Korrektur der Definitionen.


Anmelden zum Antworten