Kungl. Tekniska högskolan NADA Grundformer med Stava Språkteknologi 2D1418 Höstterminen 2004 Författare: Andreas Pettersson az@kth.se
1. Bakgrund Om man automatiskt ska plocka ut de informationsbärande orden ur ett dokument för att senare kunna söka på dem vill man ofta återföra orden på grundform. I t.ex. sökmotorer där sidorna är lagrade med de väsentliga orden i grundform ger det en bättre sökning, eftersom alla tänkbara ändelser av ordet då tas med i sökningen utan att behövas specificeras. Sökningen går därmed fortare av den orsaken att man har färre index. Stava är ett verktyg för stavningskontroll som utvecklas av Kann och Hollman inom ett projekt vid Nada, KTH. Det är en forskningsprodukt och är inte tillgängligt för användning utanför KTH. Programmet Stava 1 innehåller en särskild modul, suffix.c. Om Stava inte kan hitta ett ord direkt i någon av ordlistorna kontrollerar modulen om ordet matchar någon suffixregel. Om så är fallet accepteras ordet som rättstavat. I Stava finns suffixregler för substantiv, verb och adjektiv. Substantiv och svaga verb matchas ofta av en suffixregel. Däremot vissa former av adjektiv och starka verb kan inte Stavas suffixregler användas. Dessa ord saknar regelbunden böjning och lagras därför i lexikonen i dess olika former. För att även kunna täcka in dessa oregelbundna ord i grundformer med stav krävs en annan lösning än att använda modulen suffix.c. 2. Problem Modifiera huvudmodulen stava.c så att den för varje inmatat ord anropar funktionen CheckSuffix i modulen suffix.c, samt ändra att CheckSuffix skriver ut ordets grundform. 1 Stava finns med på webben http://www.nada.kth.se/stava 1
3. Stavas suffixregler Grunden i Stava är Svenska Akademiens Ordlista (SAOL) ca 120 000 ord. I den finns ord som, n och dockor. Ordet ns står däremot inte. Stavas suffixregler beskriver hur nya böjningsformer kan bildas ur de få böjningsformer som finns i Stavas ordlista. Suffixreglerna ligger i en textfil SLlist 2 och den läses in av Stava när programmet startas. Ett exempel för ordet ns kan se ut på följande sätt: ans Den kommer att godkänna ordet ns om orden, n och dockor finns i SAOL. En regel består av ett ingångssuffix följt av en lista av uppslagssuffix. Det tomma suffixet tecknas i en suffixregel som @. Det finns tre sätt att utöka reglernas effektivitet: 3 1. Negation av uppslagssuffix I suffixlistan kan man ange negerade uppslagssuffix inledda med tecknet ~(tilde). samma sam, ~samen Den säger till exempel att varsamma ska godkännas eftersom varsam men inte varsamen finns i ordlistan. Här har man lagt till det negerade suffixet ~samen för att förhindra att ord som balsamma ska godkännas (för balsam finns ju). 2. Bokstav som föregår suffix Man kan ange att en regel bara ska användas för ord där suffixet (närmast) föregås av en viss bokstav (eller någon av en uppsättning bokstäver). Ingångssuffixet ska då föregås av dom tillåtna bokstäverna omgärdade av [ och ]. Notationen är alltså samma som i reguljära uttryck i Unix. [uå]rna @, n, r, ~dde, ~ra n godkänner suffixet -rna endast om det föregås av u eller å. Detta innebär till exempel att ordet basturna godkänns men inte vararna. 2 SLlist ligger under katalogen /misc/tcs/language/stava/ 3 Beskrivningarna är hämtade från http://www.nada.kth.se/stava/suffixregler.html 2
Kanske ännu mer användbart är möjligheten att förbjuda vissa bokstäver före suffixet. Ingångssuffixet ska då föregås av dom förbjudna bokstäverna omgärdade av [^ och ]. [^sxz]s @, en, er n godkänner genitivsuffixet -s när det inte föregås av s, x eller z. Detta innebär till exempel att ordet films godkänns men inte sfinxs. 3. Bokstavsföljder som föregår suffix Ibland vill man förbjuda att vissa bokstavssträngar föregår suffixet. Det gör man genom att ange strängarna inom parentes och avskilda med före suffixet (och före eventuellt [ ]-uttryck). (ar)ena e, et, en, ~ar, ~er godkänner suffixet -ena när det inte föregås av ar. Detta innebär till exempel att ordet samhällena godkänns men inte altarena. Om man vill förbjuda el, en och er före suffixet -aste så inleder man regeln med (el en er)aste Det första uppslagssuffixet i högerledet är alltid ordets grundform i alla suffixregler. 3
4. Utförande Stavas suffixregler används för att generera grundformen av de inmatade orden. Det innebär att t.ex. ordet ns kommer att matcha en regel med ans i vänsterledet. Byt enligt suffixregeln ans ut ans mot a. Det blir problem med ord som, n, dockor och alla andra ord som inte matchar (uppfyller) någon suffixregel. En iakttagelse är att man kan lägga till ett s på de flesta ord och därmed matcha en regel i suffixlistan. Men den lösningen är inte att rekommendera. Fel som kan uppstå är att ordet kan få andra betydelser och att ordet fortfarande inte matchar någon regel. Den generella lösningen är att lägga till fler regler som matchar de ord som finns i ordlistan. T.ex. kan följande uppsättning av suffixregler ge grundformen av. a an or Reglerna täcker in orden, n och dockor. För att se vilka ord som godkänds av regeln kan man använda verktyget generera 4. Den tar en suffixregel och returnerar en lista på de ord som Stava därmed kommer att acceptera. 4 Generera finns på webben http://www.nada.kth.se/stava/genstava.html 4
5. Resultat Ett hyfsat resultat uppnåddes. Grundformen för de ord som används i Stavas suffixregler plockades fram. Exempel på ord Inmatat n ns dockor dockorna dockornas avlade trevliga trevligare trevligast tittas tittat tittades besatt tillgiver tillgett tillgavs Utskrift avlägga trevlig trevlig trevlig titta titta titta besätta tillge tillge tillge Däremot klarade inte programmet av oregelbundet böjda verb och pronomen eftersom de inte ingår i de ursprungliga suffixreglerna. 5
6. Referenser Jurafsky & Martin. Speech and Language Processing. ISBN 0-13-095069-6, Prentice Hall. Kann & Hollman. Manualsida för Stava. <http://www.nada.kth.se/stava/manual.html>. 14 okt 2004. Kann & Hollman. Stavas Suffixregler. <http://www.nada.kth.se/stava/suffixregler.html>. 14 okt 2004. 6
7. Appendix CheckSuffix( ) kopierades för att behålla den tidigare funktionaliteten. Den nya funktionen döps till MyCheckSuffix( ) i modulen suffix.c. /* MyCheckSuffix kollar om word innehåller suffix i suffixtabellen. För varje rad i suffixtabellen som stämmer överens kollas att ordet finns i ordlistan om suffixet byts ut mot alla kollsuffix i så fall returneras 1 och grundformen av ordet skrivs ut. Annars returneras 0 och ordet skrivs ut samt att den inte hittade någon regel som matchade suffixet. */ int MyCheckSuffix(unsigned char *word) { unsigned char word2[langd], *word2end, word3[langd]; int len = strlen((char *)word), minprefixlen = 0, firstvowel, word2len; int i,j; suffixset *suf; suffixchecklist *p; if (len < PREFIXMIN) return 0; for (; isconsonant[word[minprefixlen]]; minprefixlen++); minprefixlen++; if (minprefixlen < PREFIXMIN) firstvowel = PREFIXMIN; else firstvowel = minprefixlen; CacheCheckWord(NULL, 0); if (len > PREFIXMIN) { for (suf = FindSuffix(word, len, firstvowel, word2, &word2len); suf; suf = FindNextSuffix(word, len, firstvowel, word2, &word2len)) { strcpy(word3,word2); word2end = word2 + word2len; for (p = suf->check; p; p = p->next) { strcpy(word2end, p->checksuffix); if (CacheCheckWord(word2, word2len + p->suffixlen)!= p->accept) goto nextsuffix; //Skriver ut grundformen om det finns en matchande regel. printf("grundform: "); WriteISO(word3); WriteISO(suf->check->checksuffix); printf("\n"); return suf->accept; /* Alla villkor OK */ nextsuffix: continue; for (i = SuffixStart[0]; i < SuffixStart[1]; i++) { suf = set[i]; if (CheckEmptySuffix(suf, word, len)) { strcpy(word2, word); word2end = word2 + len; for (p = suf->check; p; p = p->next) { strcpy(word2end, p->checksuffix); if (CacheCheckWord(word2, len + p->suffixlen)!= p->accept) goto nextsuffix2; printf("grundform: "); for(j=0;j<len-suf->len;j++) printf("%c",word2[j]); printf("%s\n",suf->check->checksuffix); return suf->accept; /* Alla villkor OK */ nextsuffix2: continue; printf("ordet: %s matchade ingen regel\n",word); return 0; 7
MyCheckSuffix( ) anropas från huvudmodulen stava.c från funktionen StavaWord( ). /* StavaWord checks if a word is correctly spelled. Returns 1 if the word is correctly spelled and 0 otherwise. */ int StavaWord( const unsigned char *word ) /* word to be checked */ { unsigned char buf[langd + 3], ord2[langd + 3]; int i, bindestreck = 0; for (i = 0; i < LANGD; i++) { if (!(buf[i] = bokstavstabell[word[i]])) break; if (buf[i] == '-') bindestreck++; if (i == LANGD) return 0; /* too long word */ if (i < ORDMIN) return 1; /* short words are always accepted */ if (KollaOrd(buf)) { // MyCheckSuffix anropas med det kontrollerade ordet word. MyCheckSuffix(word); return 1; if (bindestreck) { if (xsammansatta) if (KollaDelar(buf, ord2)) return 1; SuddaBindestreck(buf, ord2); if (KollaOrd(ord2)) return 1; return 0; Ett utdrag från listan (SLlist) med suffixregler. #Egna regler a an or #Egna regler slut. as ans ors orna ornas [^sxz]s @, en, ar ens @, en, ar ars @, en, ar arna @, en, ar arnas @, en, ar es ens ars arna arnas [^n]s [^n]ns [^n]ars [^n]arna [^n]arnas... 8