C :: Aufgabe #51
2 Lösungen

Spaltenbreite und Blocksatz
Anfänger - C
von bibir
- 03.09.2014 um 08:33 Uhr
Ein vorgegebener Text soll eingelesen und in einer bestimmten Spaltenbreite wieder ausgegeben werden.
Die Spaltenbreite N wird als Eingabeparameter vorgegeben. Der Text besteht aus "Wörtern", die durch Leerzeichen (Blank) getrennt sind. Unter einem "Wort" wird hier eine beliebige zusammenhängende Zeichenkette verstanden, wobei jedes Zeichen eine Druckstelle einnimmt.
Der Text soll ausgerichtet werden an den beiden Spaltenrändern, und die zusätzlich einzuführenden Blanks sollen möglichst gleichmäßig auf die Zwischenräume zwischen den Wörtern verteilt werden.
Der Text beginnt in einer Spalte grundsätzlich linksbündig, Wörter, die länger sind als die Spaltenbreite, werden am rechten Rand ohne Trennzeichen zwangsweise getrennt. Silbentrennung darf nicht durchgeführt werden.
Die Spaltenbreite N wird als Eingabeparameter vorgegeben. Der Text besteht aus "Wörtern", die durch Leerzeichen (Blank) getrennt sind. Unter einem "Wort" wird hier eine beliebige zusammenhängende Zeichenkette verstanden, wobei jedes Zeichen eine Druckstelle einnimmt.
Der Text soll ausgerichtet werden an den beiden Spaltenrändern, und die zusätzlich einzuführenden Blanks sollen möglichst gleichmäßig auf die Zwischenräume zwischen den Wörtern verteilt werden.
Der Text beginnt in einer Spalte grundsätzlich linksbündig, Wörter, die länger sind als die Spaltenbreite, werden am rechten Rand ohne Trennzeichen zwangsweise getrennt. Silbentrennung darf nicht durchgeführt werden.
Lösungen:
Lösung 1 mit den traditionellen C-String- und Ausgabefunktionen. Hat Probleme bei der Darstellung von Texten mit Sonderzeichen (z.B. Umlaute).
Aufrufbeispiel: englischer Text, Spaltenbreite 72:
C-Code
Aufrufbeispiel: englischer Text, Spaltenbreite 72:
Konsolenausgabe:
$ ./blocksatz "$(cat en.txt)" 72
The goal of the Linux Documentation Project (LDP) is to create and
distribute a canonical set of high quality free GNU/Linux documentation.
An additional goal is to collaborate on all issues of GNU/Linux
documentation. We hope to establish a high quality system of
documentation that is easy to use and search. This includes integration
of a commented list of all the major documentation sites with similar
goals. The LDP is essentially a loose team of volunteers with minimal
central organization. Anyone who would like to help is welcome to join
...

/********************************************* * blocksatz.c Textformatierung im Blocksatz *********************************************/ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <ctype.h> #include <string.h> #define LINE_BUFFER_SIZE 200 #define WORDS_PER_LINE 50 // Spaltenbreite global int gcolumn_width; // Textparser (Wortsuche) char* parse_text(char *start, int maxlen, int backstep) { static char *w; // begin of word static char *p; // pointer to next char static char csav=0; // char replaced by '\0' if (csav) { *p = csav; csav = 0; } if (backstep) return (w)?p=w:NULL; if (start) p = start; while (*p && isspace(*p)) p++; w = p; while (*p && !isspace(*p) && p - w < maxlen) p++; if (*p) { csav = *p; *p = '\0'; } return (p - w)?w:NULL; } // Hole naechstes Wort mit Maximallaenge char *getword(char *word, int maxlen) { return parse_text(word, maxlen, 0); } // Letztes Wort wieder einstellen char *ungetword(void) { return parse_text(NULL, 0, 1); } // Ausgabe einer Textzeile im Blocksatz // nwrd : Anzahl Worte // nspc : Anzahl Blanks zur Verteilung // words : Zeiger auf Wortliste void print_line(int nwrd, int nspc, char **words) { int min_spc, res_spc; int gap, ng, nw; --nwrd; min_spc = (nwrd && nspc) ? (nspc/nwrd) : 1; res_spc = nspc - min_spc*nwrd; for (nw=0; nw<=nwrd; nw++) { printf("%s", words[nw]); if (nw < nwrd) { gap = min_spc + ((nwrd-nw<=res_spc)?1:0); for (ng=0; ng<gap; ng++) putchar(' '); } } putchar('\n'); } // Hauptfunktion: Textformatierung im Blocksatz void format_text(char *text) { char line_buffer[LINE_BUFFER_SIZE]; char *words_list[WORDS_PER_LINE]; char *word, *lbpos; int cwords = 0; int clines = 0; int cleft, wlen; lbpos = line_buffer; cleft = gcolumn_width; if ((word = getword(text, gcolumn_width)) != NULL) { do { wlen = strlen(word); memcpy(lbpos, word, wlen+1); words_list[cwords++] = lbpos; lbpos += wlen + 1; cleft -= wlen; if (cleft < cwords) { if (cleft < cwords-1) { ungetword(); cleft += wlen; cwords--; } print_line(cwords, cleft, words_list); clines++; cwords = 0; cleft = gcolumn_width; lbpos = line_buffer; } } while ((word = getword(NULL, gcolumn_width)) != NULL); } if (cwords > 0) { print_line(cwords, 0, words_list); clines++; } printf("column width %d, total %d lines\n", gcolumn_width, clines); } // main int main(int argc, char **argv) { char *ptext; int iopt; if (argc > 1) { iopt = (argc==2)?0:2; gcolumn_width = (iopt)?atoi(argv[iopt]):60; if ((ptext = strdup(argv[1])) != NULL) { format_text(ptext); free(ptext); } } return 0; }
Lösung 2 verwendet die "Wide Character String"-Funktionen und stellt auch Texte mit Sonderzeichen korrekt dar.
Aufrufbeispiel: deutscher Text, Spaltenbreite 72:
C-Code
Aufrufbeispiel: deutscher Text, Spaltenbreite 72:
Konsolenausgabe:
$ ./wblocksatz "$(cat ge.txt)" 72
Die Ursprünge des heutigen Internet reichen in die 60er Jahre zurück. Es
war die Zeit des Kalten Krieges zwischen den beiden Weltmächten USA und
UdSSR. Neue Impulse in der Elektronischen Datenverarbeitung (EDV) kamen
in jener Zeit hauptsächlich durch militärische Initiativen zustande.
Mittlerweile gibt es im Internet Proteste gegen die Auffassung,
militärische Interessen hätten das Internet geboren. Das ist insofern
berechtigt, als es keine unmittelbare Ursachen-Wirkungs-Verhältnisse
gibt. Doch die technologischen Ideen und Entwicklungen der
Vorläufernetze kamen definitiv aus dem militärnahen Umfeld in den USA,
und es ist deshalb auch nicht verkehrt, das so darzustellen. Im
Department of Defense, dem amerikanischen Verteidigungsministerium,
wurde seit den frühen 60er Jahren überlegt, wie man wichtige
militärische Daten besser schützen könnte. Selbst bei einem atomaren
Angriff des Gegners sollten die Daten nicht zerstört werden können. Als
Lösung kam nur ein elektronisches Datennetz in Frage. Die gleichen Daten
sollten dabei auf mehreren, weit entfernten Rechnern abgelegt werden.
Bei neuen oder geänderten Daten sollten sich alle angeschlossenen
Rechner binnen kürzester Zeit den aktuellen Datenstand zusenden. Jeder
...

/**************************************************** * wblocksatz.c Textformatierung im Blocksatz * wcs-Variante (wide character strings) ****************************************************/ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <wchar.h> #include <wctype.h> #include <locale.h> #define LINE_BUFFER_SIZE 200 #define WORDS_PER_LINE 50 // Spaltenbreite global int gcolumn_width; // Textparser (Wortsuche) wchar_t* wparse_text(wchar_t *start, int maxlen, int backstep) { static wchar_t *w; // begin of word static wchar_t *p; // pointer to next char static wchar_t csav=0; // char replaced by '\0' if (csav) { *p = csav; csav = 0; } if (backstep) return (w)?p=w:NULL; if (start) p = start; while (*p && iswspace(*p)) p++; w = p; while (*p && !iswspace(*p) && p - w < maxlen) p++; if (*p) { csav = *p; *p = L'\0'; } return (p - w)?w:NULL; } // Hole naechstes Wort mit Maximallaenge wchar_t *wgetword(wchar_t *word, int maxlen) { return wparse_text(word, maxlen, 0); } // Letztes Wort wieder einstellen wchar_t *wungetword(void) { return wparse_text(NULL, 0, 1); } // Ausgabe einer Textzeile im Blocksatz // nwrd : Anzahl Worte // nspc : Anzahl Blanks zur Verteilung // words : Zeiger auf Wortliste void wprint_line(int nwrd, int nspc, wchar_t **words) { int min_spc, res_spc; int gap, ng, nw; --nwrd; min_spc = (nwrd && nspc) ? (nspc/nwrd) : 1; res_spc = nspc - min_spc*nwrd; for (nw=0; nw<=nwrd; nw++) { wprintf(L"%ls", words[nw]); if (nw < nwrd) { gap = min_spc + ((nwrd-nw<=res_spc)?1:0); for (ng=0; ng<gap; ng++) putwchar(L' '); } } putwchar(L'\n'); } // Hauptfunktion: Textformatierung im Blocksatz void wformat_text(wchar_t *text) { wchar_t line_buffer[LINE_BUFFER_SIZE]; wchar_t *words_list[WORDS_PER_LINE]; wchar_t *word, *lbpos; int cwords = 0; int clines = 0; int cleft, wlen; lbpos = line_buffer; cleft = gcolumn_width; if ((word = wgetword(text, gcolumn_width)) != NULL) { do { wlen = wcslen(word); wmemcpy(lbpos, word, wlen+1); words_list[cwords++] = lbpos; lbpos += wlen + 1; cleft -= wlen; if (cleft < cwords) { if (cleft < cwords-1) { wungetword(); cleft += wlen; cwords--; } wprint_line(cwords, cleft, words_list); clines++; cwords = 0; cleft = gcolumn_width; lbpos = line_buffer; } } while ((word = wgetword(NULL, gcolumn_width)) != NULL); } if (cwords > 0) { wprint_line(cwords, 0, words_list); clines++; } wprintf(L"column width %d, total %d lines\n", gcolumn_width, clines); } // main int main(int argc, char **argv) { wchar_t *wcsbuf; int iopt; size_t maxchr; if (argc > 1) { iopt = (argc==2)?0:2; gcolumn_width = (iopt)?atoi(argv[iopt]):60; setlocale(LC_ALL, "de_DE.utf8"); if (fwide(stdout,1) >= 0) { maxchr = strlen(argv[1])+1; if ((wcsbuf = (wchar_t *)malloc(maxchr * sizeof(wchar_t))) != NULL) { if (mbstowcs(wcsbuf, argv[1], maxchr) > 0) wformat_text(wcsbuf); free(wcsbuf); } } else printf("stdout is byte oriented.\n"); } return 0; }