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

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.
#2
vote_ok
von devnull (8870 Punkte) - 15.10.2014 um 07:57 Uhr
Lösung 2 verwendet die "Wide Character String"-Funktionen und stellt auch Texte mit Sonderzeichen korrekt dar.
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
...


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

Kommentare:

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

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