Ersetzen von Tabulator durch Leerzeichen
-
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\tabcAusgabe
567 abc
234567 abc
23456789 abc
123456789012345 abcAlso 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\tabcAusgabe
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:
-
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 mitsize_t
zu tun, wenn _M_X64 definiert ist?
Und was hat %u mitsize_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 manint
²
Und in deinem Programm reichtint
aus.
-
DirkB schrieb:
Dann ist das immer noch falsch. [...] %lu steht für
unsigned long
.Schau dir den letzten EDIT an.
-
size_t s; printf("%llu", (unsigned long long)s);
?
-
@SeppJ: Ist
long long
nicht wieder in C99 eingeführt worden?
-
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, abersize_t
64 Bit. Und nicht nur beiprintf
, sondern auch beisprintf
,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.