/****************************************************************************/ /* ** M J O N O T . C ** ** Yleisi„ merkkijonojen k„sittelyyn liittyvi„ aliohjelmia. ** ** Aliohjelmat: ** tee_jono - luo uuden merkkijonon jonne jono kopioidaan ** kopioi_jono - kopioi kork. annetun m„„r„n merkkej„ ** liita_jono - liitt„„ jonon toisen per„„n, tulos ** korkeintaan max.pituus mittainen ** f_lue_jono - lukee tiedostosta merkkijonon ** lue_jono - lukee p„„tteelt„ merkkijonon ** lue_jono_oletus - lukee p„„tteelt„ merkkijonon. ** N„ytt””n tulostetaan haluttu viesti ja ** jonon oletusarvo, mik„li painetaan RET ** lue_kokluku_oletus - luetaan kokonaisluku, jolle k„ytet„„n oletusarvoa ** mik„li heti painetaan RET ** poista_alkutyhjat - poistaa merkkijonon alussa olevat v„lily”nnit ** poista_lopputyhjat - poistaa merkkijonon lopussa olevat v„lil. ** poista_2_tyhjat - muuttaa merkkijonossa kaikki per„kk„iset ** v„lily”nnit yhdeksi v„lily”nniksi ** poista_tyhjat - poistaa alusta ja lopusta kaikki sek„ ** muualta moninkertaiset v„lily”nnit ** isoksi - muuttaa kirjaimen isoksi kirjaimeksi huomioiden ** skandit ** pieneksi - muuttaa pieneksi huomioiden skandit ** jono_isoksi - muuttaa jonon kaikki merkit isoiksi ** jono_pieneksi - muuttaa jonon kaikki merkit pieniksi ** jono_alku_isoksi - muuttaa jonon kaikki sanojen alut isoiksi ** ja kaikki muut pieniksi ** wildmat - vertaa onko sana == maski, miss„ maskissa ** voi olla jokeri-merkkej„ (* tai ?) ** palanen - ottaa merkkijonosta seuraavan erotinmerkkien ** m„„r„„m„n palasen ** laske_merkit - laskee annettujen merkkien esiintymism„„r„n ** merkkijonossa */ /* HUOM! T„ss„ tiedostossa olevien DEMO-teht„vien return-lauseet ovat vain h„m„yst„, jotta jokaista parametrina tuotua muuttujaa tulisi k„ytetty„ v„hint„„n 1. kerran (=> ei k„„nt„j„n valituksia). */ #include #include #include #include #include "mjonot.h" char *VALIMERKIT=" .,-;:?!"; /****************************************************************************/ char /* = jonon kopion osoite */ *tee_jono( /* NULL = ei voida kopioida */ char *jono /* s Kopioitava merkkijono */ ) /* ** Funktiolla varataan jonon kokoinen uusi tila ja jono kopioidaan sinne. ** Palautetaan uuden jonon osoite. ** ** Kutsuu: malloc ----------------------------------------------------------------------------*/ { /* DEMO tee_jono XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ int /* */ kopioi_jono( /* 0 = onnistui, muu = kaikki ei mahtunut */ char *tulos ,/* t Jono jonne kopioidaan */ int max_koko ,/* s Tuloksen maksimikoko */ char *jono /* s Kopioitava merkkijono */ ) /* ** Funktiolla kopioidaan merkkijono. Mik„li jono ei mahdu sille ** varattuun tilaan, katkaistaan jono. ** ** Kutsuu: strncpy ----------------------------------------------------------------------------*/ { /* DEMO kopioi_jono XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return max_koko==0 && tulos && jono; } /****************************************************************************/ int /* */ liita_jono( /* 0 = onnistui, 1 = kaikki ei mahtunut */ char *tulos ,/* s,t Jono jonne liitet„„n */ int max_koko ,/* s Tuloksen maksimikoko */ char *jono /* s Kopioitava merkkijono */ ) /* ** Funktiolla liitet„„n merkkijono tuloksen per„„n. Mik„li jono ei mahdu ** sille varattuun tilaan, katkaistaan jono. ----------------------------------------------------------------------------*/ { /* DEMO liita_jono XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return max_koko==0 && tulos && jono; } /****************************************************************************/ int /* 2 = jono sy”tettiin */ f_lue_jono( /* 1 = jono ei mahtunut */ /* 0 = painettiin heti RETURN */ /* -1 = */ /* -2 = virhe sy”t”ss„ */ FILE *f, /* s Tiedosto josta luetaan */ char *jono, /* t Merkkijono johon luetaan */ int max_pituus /* s Luettavien merk. max.lkm+1 (tila \0) */ ) /* ** Funktiolla luetaan tiedoston yhdelt„ rivilt„ korkeintaan ** max_pituus -mittainen merkkijono. Jonoon ei tule \n -merkki„. ** Tiedoston ollessa loppu palautetaan -1 mutta itse jonoon ei kosketa. ** Mik„li rivill„ ei yht„„n merkki„, palautetaan 0 samoin kuin jonona. ** Rivin loppuosa, joka ei mahdu jonoon h„vitet„„n. ** ** Sy”tt”: tiedostosta ** Tulostus: n„yt”lle jos stdin ** Tekij„: Vesa Lappalainen ** Pvm: 9.10.1991 ** Esimerkki: Kutsu f_lue_jono(f,jono,8) ** Tiedostossa rivit: palauttaa ** 1234567890123456789 jonon pituus f_lue_jono jono ** Kissa puussa 7 1 Kissa p\0 ** istuu 5 2 istuu\0 ** 0 0 \0 ** ja ihmettelee. 7 1 ja ihme\0 ** Joo! 4 2 Joo!\0 **- seuraava kutsu 4 -1 Joo!\0 ----------------------------------------------------------------------------*/ { int jonon_pituus,c; if ( feof(f) ) return TIEDOSTO_LOPPU; if ( fgets(jono,max_pituus,f)==NULL ) return VIRHE_SYOTOSSA; jonon_pituus = strlen(jono); if ( jono[jonon_pituus-1]=='\n' ) { /* Poistetaan mahd. \n */ jonon_pituus--; jono[jonon_pituus]=0; if ( jonon_pituus==0 ) return OLETUS; return SYOTTO_OK; } /* Erikoistapaukset: */ /* Jos jono loppui ja tiedosto samalla, ei tietenk„„n ole \n ja mahtui */ if ( feof(f) ) return SYOTTO_OK; /* Jos jonosta loppui tila samalla kun vain \n j„i lukematta */ c=fgetc(f); if (c=='\n') return SYOTTO_OK; while ( ((c=fgetc(f))!=EOF) && (c!='\n') ); /* Poistetaan rivin loppu. */ return EI_MAHDU; } /****************************************************************************/ int lue_jono(char *jono,int max_pituus) /* ** Funktiolla luetaan p„„tteelt„ yhden rivin mittainen merkkijono. ** Muuten ks. f_lue_jono. ** Sy”tt”: p„„tteelt„ ** Tulostus: n„yt”lle ----------------------------------------------------------------------------*/ { /* DEMO lue_jono XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return (max_pituus==0) && (jono); } /****************************************************************************/ int /* 2 = jono sy”tettiin */ lue_jono_oletus( /* 1 = jono ei mahtunut */ /* 0 = tyhj„ rivi */ /* -1 = */ /* -2 = virhe sy”t”ss„ */ char *hopute, /* s Teksti joka tulostetaan kysymykseksi. */ int oletus_alku, /* s Sarake josta oletusarvo alkaa. (0=heti) */ int jonon_alku, /* s Sarake johon > tulee. (0=heti.) */ char *oletus, /* s Merkkijonon oletusarvo. */ char *jono, /* t Palautettava merkkijono. */ int max_pituus /* s Palautettavan jonon maksimipituus. */ ) /* ** Funktiolla luetaan p„„tteelt„ yhden rivin mittainen merkkijono. ** Mik„li vastataan pelkk„ [Ret] palautetaan oletusjono. ** Hoputteeksi tulostetaan teksti 'hopute (oletus) >' ** Negatiiviset arvot oletus_alku ja jonon_alku sarakkeilla tarkoittavat ** et„isyytt„ (itseisarvo) edellisest„ merkist„. ** Muuten ks. f_lue_jono ** Sy”tt”: p„„tteelt„ ** Tulostus: n„yt”lle ** Kutsuu: f_lue_jono ** Esimerkki: ** Kutsu: lue_jono_oletus("Anna j„senen nimi",19,33,"Ankka Aku",nimi,30) ** 19 33 ** Anna j„senen nimi (Ankka Aku) >Ankka Tupu ** Palautetaan: 2 sek„ nimi = "Ankka Tupu" ----------------------------------------------------------------------------*/ { char oletus_kopio[80]; /* Kopio oletusjonosta jotta oletus voi olla jono */ int oletus_pituus,hopute_pituus, tyhjat_h_s,tyhjat_s_v,palautus; strncpy(oletus_kopio,oletus,80-1); oletus_kopio[80-1]='\0'; hopute_pituus = strlen(hopute); oletus_pituus = strlen(oletus_kopio); /* Tyhji„ hoputetekstin ja oletuksen vasemman sulun v„liin */ tyhjat_h_s = oletus_alku - hopute_pituus - 1; if ( tyhjat_h_s <= 0 ) tyhjat_h_s = 1; if ( oletus_alku < 0 ) tyhjat_h_s = -oletus_alku; /* Tyhji„ oletuksen oikean sulun ja v„k„sen v„liin */ tyhjat_s_v = jonon_alku - (hopute_pituus+tyhjat_h_s+1+oletus_pituus+1) - 1; if ( tyhjat_s_v <= 0 ) tyhjat_s_v = 0; if ( jonon_alku < 0 ) tyhjat_s_v = -jonon_alku; printf("%s" "%*s" "(%s)" "%*s" ">", hopute,tyhjat_h_s,"",oletus_kopio,tyhjat_s_v,""); if ( (palautus = lue_jono(jono,max_pituus)) != OLETUS ) return palautus; kopioi_jono(jono,max_pituus,oletus_kopio); return OLETUS; } /****************************************************************************/ int /* 2 = sy”tettiin */ lue_kokluku_oletus( /* 1 = annettiin liian iso sy”tt” */ /* 0 = tyhj„ rivi */ /* -1 = */ /* -2 = virhe sy”t”ss„ */ int oletus_luku, /* s Luvun oletusarvo. */ int *luku /* t Luettu luku. */ ) /* ** Funktiolla luetaan kokonaisluku. ** Mik„li painetaan heti CR tai j„rkev„„ lukua ei ole, palautetaan oletusarvo. ** Kutsuu: lue_jono ----------------------------------------------------------------------------*/ { int palautus,i; char st[20]; *luku = oletus_luku; if ( (palautus=lue_jono(st,20)) <= OLETUS ) return palautus; if ( !sscanf(st,"%d",&i) ) return VIRHE_SYOTOSSA; *luku = i; return palautus; } /****************************************************************************/ char /* */ *poista_alkutyhjat( /* = Muutettu jono */ char *jono /* t Muutettu jono */ ) /* ** Funktiolla poistetaan merkkijonosta alussa olevat v„lily”nnit ** ** Algoritmi: Siirret„„n jonoa alkutyhjien verran taaksep„in. ** Esimerkki: " kissa " -> "kissa " ----------------------------------------------------------------------------*/ { /* DEMO poista_alkutyhjat XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ char /* */ *poista_lopputyhjat( /* = Muutettu jono */ char *jono /* s,t Muutettu jono */ ) /* ** Funktiolla poistetaan merkkijonosta lopussa olevat v„lily”nnit ** ** Algoritmi: Siirret„„n merkkijono loppumerkki 1. ei-tyhj„n per„„n. ** Esimerkki: " kissa " -> " kissa" ----------------------------------------------------------------------------*/ { /* DEMO poista_lopputyhjat XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ char /* */ *poista_2_tyhjat( /* = Muutettu jono */ char *jono /* s,t Muutettu jono */ ) /* ** Funktiolla poistetaan merkkijonosta moninkertaiset v„lily”nnit. ** ** Algoritmi: K„ytet„„n kahta osoitinta luku ja kirjoitus, ** Merkki kopioidaan lukupaikasta kirjoituspaikkaan kun ** ei ole moninkertaista tyhj„„, t„ll”in my”s kasvatetaan ** kirjoituspaikkaa. ** luku-osoitinta siirret„„n aina eteenp„in. ** Esimerkki: "k is sa" -> "k is sa" ** ^ ^ ** k l ----------------------------------------------------------------------------*/ { /* DEMO poista_2_tyhjat XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ char /* */ *poista_tyhjat( /* = Muutettu jono */ char *jono /* s,t Muutettu jono */ ) /* ** Funktiolla poistetaan merkkijonosta kaikki alku ja lopputyhj„t ** sek„ moninkertaiset tyhj„t jonon keskelt„. ** ** Kutsuu: poista_alkutyhjat ** poista_lopputyhjat ** poista_2_tyhjat ** Esimerkki: " kis sa " -> "kis sa" ----------------------------------------------------------------------------*/ { /* DEMO poista_tyhjat XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ char /* */ isoksi( /* Muutetaan kirjain vast. isoksi kirjaimeksi. */ char c /* s Muutettava kirjain. */ ) /* ** Funktiolla muutetaan pienet kirjaimet isoiksi. My”s skandit toimivat ** Algoritmi: K„sitell„„n skandit erikoistapauksena. ----------------------------------------------------------------------------*/ { switch (c) { case '†': return '¸'; case '„': return 'ˇ'; case '”': return '™'; } /* N„in: if ( c<'a' ) return c; if ( c>'z' ) return c; return c-('a'-'A'); tai: */ return toupper(c); } /****************************************************************************/ char /* */ pieneksi( /* Muutetaan kirjain vast. pieneksi kirjaimeksi. */ char c /* s Muutettava kirjain. */ ) /* ** Funktiolla muutetaan isot kirjaimet pieniksi. My”s skandit toimivat ** Algoritmi: K„sitell„„n skandit erikoistapauksena. ----------------------------------------------------------------------------*/ { /* DEMO pieneksi XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return c; } /****************************************************************************/ char /* */ *jono_pieneksi( /* Muutetaan jono pienill„ kirjoitetuksi. */ char *jono /* s,t Muutettava jono. */ ) /* ** Funktiolla muutetaan merkkijonon isot kirjaimet pieniksi. My”s skandit. ** Kutsuu: pieneksi ----------------------------------------------------------------------------*/ { /* DEMO jono_pieneksi XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ char /* */ *jono_isoksi( /* Muutetaan jono isoilla kirjoitetuksi. */ char *jono /* s,t Muutettava jono. */ ) /* ** Funktiolla muutetaan merkkijonon pienet kirjaimet isoiksi. My”s skandit. ** Kutsuu: isoksi ----------------------------------------------------------------------------*/ { /* DEMO jono_isoksi XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ char /* */ *jono_alku_isoksi( /* Muutetaan jonon sanojen alut isoiksi, muut pien*/ char *jono /* s,t Muutettava jono. */ ) /* ** Funktiolla muutetaan jonon sanojen 1. kirjaimet isoiksi. Sanan kaikki ** muut muutetaan pieniksi. ** ** Kutsuu: isoksi ** pieneksi ** Algoritmi: V„limerkkien j„lkeen seuraava kirjain muutetaan aina ** isoksi. Muuten pieneksi. ** Esimerkki: "iso paha SUSI" -> "Iso Paha Susi" ----------------------------------------------------------------------------*/ { /* DEMO jono_alku_isoksi XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return jono; } /****************************************************************************/ int /* */ wildmat( /* 0 = jono t„sm„„ maskiin */ /* 1 = jono ei t„sm„„ maskiin */ register char *s ,/* s Tutkittava jono */ register char *p /* s Maski, johon jonoa verrataan */ ) /* ** Funktiolla tutkitaan t„sm„„k” annettu jono verrattavaan maskiin. ** Maski saa sis„lt„„ seuraavia erikoismerkkej„: ** * vastaa 0-n merkki„ ** ? vastaa mit„ tahansa yht„ merkki„ ** ** Algoritmi: Kysymysmerkki ja tavallinen kirjain normaalisti ** Jos tulee vastaan t„hti joka ei ole jonon lopussa, ** niin ongelmahan on oikeastaan ** (koska t„h„n asti kaikki on ollut oikein) ** "Onko loppujono sama kuin toisen jonon loppu JOSTAKIN ** kohdasta alkaen"? ** Siis kokeillaan sovittaa loppujonoa aliohjelman itsens„ ** (rekursio) avulla kaikkiin mahdollisiin loppupaikkoihin. ** Esimerkki: s = "Kissa" p = "*ss*" -> 0 ** = "*ss" -> 1 ----------------------------------------------------------------------------*/ { while (*p) { /* Jos kokeiltavaa jonoa on j„ljell„ */ if (*p == '?') { /* Jos kysymysmerkki, niin kaikki kelpaa */ if (!*s) return 1; /* paitsi jos jono on loppunut! */ } else if (*p == '*') { /* Jos * niin katsotaan onko viimeinen */ if (*++p) /* Jollei * viimeinen, niin kokeillaan */ while (wildmat(s, p)) /* loppujonoa jokaiseen eri paikkaan. */ if (!*++s) return 1; /* Jos jono loppuu kesken niin ei t„sm„„! */ return 0; /* Muuten samat (* viimeinen tai loppujono*/ } /* t„sm„si) */ else if (*s != *p) /* Jos samat merkit niin tietysti OK! */ return 1; s++; p++; /* Kummassakin jonossa eteenp„in */ } return *s; /* Jos jono loppui yht„aikaa, niin OK! */ } /****************************************************************************/ char /* */ *palanen( /* Osoitin merkkijonon palaseen. */ char *jono ,/* s P„tkitt„v„ jono, turmeltuu! */ char *erottimet ,/* s Merkit joiden kohdalta katkaistaan. */ int *jaljella /* t Paljonko jonoa on viel„ j„ljell„ (-1 loppu)*/ ) /* ** Funktiolla p„tkit„„n merkkijonoa osiin. 1. kutsukerralla v„litet„„n ** tutkittava jono ja t„m„n j„lkeen seuraavilla NULL osoitin. ** Funktio vaihtaa l”yt„m„ns„ erotinmerkit NUL-merkeiksi! ** ** string.h-kirjaston strtok-funktiosta palanen eroaa siin„, ** ett„ strtok palauttaa jonosta "Aku|Ankka||12" 3 jonoa ja ** palanen 4. Siis strtok sopii paremmin v„lily”ntien kohdalta ** paloitteluun. Palanen palauttaa jonon loputtua aina osoitinta ** tyhj„„n jonoon, strtok NULL-jonon. Siis palanen on turvallisempi ** jos halutaan aina l”yt„„ v„hint„„ n-kappaletta jonoja. ** ** Muuttuu: jono ** Algoritmi: ** Esimerkki: 012345678901234 ** jono="Aku|Ankka||12" erottimet="|" ** 1. kutsu palanen(jono,"|",&j) -> "Aku" , j=9 ** 2. kutsu palanen(NULL,"|",&j) -> "Ankka", j=3 ** 3. kutsu palanen(NULL,"|",&j) -> "" , j=2 ** 4. kutsu palanen(NULL,"|",&j) -> "12" , j=0 ** 5. kutsu palanen(NULL,"|",&j) -> "" , j=-1 ----------------------------------------------------------------------------*/ { static char *st; static int p1,p2,pit; if (jono) { /* 1. kutsukerta, alustetaan apumuuttujat */ st = jono; pit = strlen(jono); p1 = 0; } else p1 = p2+1; /* Muilla kerroilla jatketaan siit„ mihin viim. j„„tiin. */ if ( p1 > pit ) { *jaljella = -1; return st+pit; /* Tyhj„ merkkijono, kun osoitetaan jonon NUL-tavuun. */ } p2 = p1+strcspn(st+p1,erottimet); st[p2] = 0; *jaljella = pit-p2; return st+p1; } /****************************************************************************/ int /* */ laske_merkit( /* Merkkien lukum„„r„ jonossa. */ char *jono ,/* s Jono josta merkkej„ lasketaan. */ char *merkit /* s Merkit joita etsit„„n. */ ) /* ** Funktiolla lasketaan annettujen merkkien yhteinen esiintymism„„r„ ** merkkijonossa. ** ** Esimerkki: jono = "Kissa" merkit = "is" -> laske_merkit = 3 ** jono = "Kissa" merkit = "ss" -> laske_merkit = 2 ----------------------------------------------------------------------------*/ { /* DEMO laske_merkit XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return merkit && jono; } /****************************************************************************/ int /* -1 = ei l”ydy */ paikka( /* muut = 1. l”ytymispaikan indeksi */ char *jono ,/* s Jono josta merkki„ etsit„„n. */ char merkki /* s merkki jota etsit„„n */ ) /* ** Funktiolla palautetaan etsitt„v„n merkin 1. indeksi merkkijonossa. ** ** Esimerkki: jono = "Kissa" merkki='s' -> 2 ** jono = "Koira" merkki='s' -> -1 ----------------------------------------------------------------------------*/ { /* DEMO paikka XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ return merkki && jono; }