C :: Aufgabe #51 :: Lösung #1

2 Lösungen Lösungen öffentlich
#51

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.
#1
vote_ok
von devnull (8870 Punkte) - 15.10.2014 um 07:49 Uhr
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:

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
...


Quellcode ausblenden C-Code
/*********************************************
 * 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;
}

Kommentare:

Für diese Lösung gibt es noch keinen Kommentar

Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben