Kirjautuminen

Haku

Tehtävät

Koodit: C: Word wrap

Kirjoittaja: hunajavohveli

Kirjoitettu: 30.08.2008 – 30.08.2008

Tagit: teksti, koodi näytille, vinkki

Word wrap on toimenpide, joka jakaa tekstin automaattisesti useammalle riville sen mukaan, kuinka pitkiä rivejä ruudulle kerralla mahtuu. Graafisten käyttöliittymien valmiissa komponenteissa word wrap on suorastaan itsestäänselvyys, mutta joskus on tarve koodata sopiva algoritmi itse. Tässä esitellyt word wrap -funktiot käyttävät ns. ahnetta algoritmia, joka sijoittaa riville niin paljon sanoja kuin mahdollista ja siirtyy sitten seuraavaan riviin toistaakseen saman. Optimaalisemmat algoritmit pyrkivät minimoimaan rivien loppuun jäävän tyhjän tilaan.

Toimintaperiaate on yksinkertainen: Algoritmi lukee merkkejä yksi kerrallaan pitäen kirjaa viimeksi luetun välilyönnin sijainnista. Kun merkkejä on luettu enemmän kuin riville mahtuu, viimeksi luettu välilyönti korvataan rivivaihdolla. Sana, jota oltiin lukemassa, kun rivi tuli täyteen, siirretään seuraavalle riville, ja merkkien lukemista jatketaan. Jälkimmäinen funktio poikkeaa ensimmäisestä siten, että se muodostaa jokaisesta rivistä oman merkkijononsa lisäämällä rivivaihdon sijaan lopetusmerkin ja kirjoittamalla taulukkoon jokaisen rivin alkuosoitteen. Funktiot on kirjoitettu monospace-fontille, mutta pienillä muutoksilla ne saa toimimaan myös vaihtelevan mittaisille merkeille.

// Yksinkertainen word wrap, korvaa sopivat välilyönnit rivivaihtomerkillä.
// Parametreina annetaan osoitin tekstiin sekä rivin maksimipituus. Jos
// teksti sisältää maksimipituutta pidemmän sanan, riviä ei katkaista.
void WordWrap(char *text, int max_line_len)
{
	int line_len = 0;	// Tähän asti luetun rivin pituus
	int space = -1;		// Viimeisin löydetty välilyönti (-1 = ei löydetty vielä)
	int i;

	// Käydään läpi tekstiä merkki kerrallaan, kunnes kohdataan lopetusmerkki.
	for(i = 0; text[i] != '\0'; i++) {
		if(text[i] == ' ') space = i;		// Pidetään kirjaa viimeksi kohdatun välilyönnin sijainnista

		if(++line_len > max_line_len && space != -1) {		// Jos luetun rivin pituus ylittää maksimin
															// ja välilyönti on löydetty
			text[space] = '\n';			// Korvataan viimeisin välilyönti rivivaihdolla.
			line_len = i - space;		// Seuraavaa riviä on jo luettu nykyisen lukukohdan
										// ja katkaisukohdan erotuksen verran.
			space = -1;					// Seuraava katkaisukohta ei vielä tiedossa
		}
	}
}
// Toimii samoin kuin ylempi, mutta rivivaihdon sijaan välilyönti korvataan lopetusmerkillä.
// Lisäksi annettuun lines-taulukkoon kirjoitetaan osoitin jokaisen rivin alkuun. Viimeinen
// parametri kertoo, montako osoitinta voidaan enintään kirjoittaa. Paluuarvo on rivien määrä.
int WordWrap2(char *text, int max_line_len, char **lines, int max_line_count)
{
	int line_count = 1;		// Rivien määrä
	int line_len = 0;
	int space = -1;
	int i;

	lines[0] = text;	// Ensimmäinen rivi alkaa samasta kohdasta kuin koko teksti

	for(i = 0; text[i] != '\0'; i++) {
		if(text[i] == ' ') space = i;

		if(++line_len > max_line_len && space != -1) {
			text[space] = '\0';							// Tällä kertaa korvataan väli lopetusmerkillä
			line_len = i - space;
			if(line_count == max_line_count) break;		// Jos maksimirivimäärä täynnä, lopetetaan
			lines[line_count] = text + space + 1;		// Uusi rivi alkaa välilyönnin jälkeisestä merkistä
			line_count++;
			space = -1;
		}
	}

	return line_count;		// Palautetaan rivimäärä
}
// Esimerkkiohjelma
#include <string.h>
#include <stdio.h>


int main(void)
{
	// Esimerkkitekstiä
	char *text =
		"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

	char str[512], *lines[20];
	int line_count, i;

	strcpy(str, text);		// Kopioidaan teksti taulukkoon, jonka sisältöä voidaan muokata
	WordWrap(str, 64);		// Wrapataan käyttäen maksimipituutena 64 merkkiä
	printf("%s\n", str);	// Tulostetaan

	strcpy(str, text);								// Kopioidaan teksti uudelleen
	line_count = WordWrap2(str, 40, lines, 7);		// Tällä kertaa otetaan kaikki rivit taulukkoon

	for(i = 2; i < line_count; i++) {				// Tulostetaan rivit 2-6
		printf("        %i. %s\n", i, lines[i]);	// lisäten sisennys ja numerointi
	}

	return 0;
}

Kommentit

Zeeli [05.09.2008 22:10:18]

#

Loistavaa!

Juice [13.09.2008 14:41:49]

#

Yksinkertainen on kaunista.

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta