4 * author: Evren (Kapusuz) Çilden
5 * email: evren.kapusuz at gmail.com
6 * version: 1.0 (15.01.2007)
9 * stems nominal verb suffixes
10 * stems nominal inflections
11 * more than one syllable word check
12 * (y,n,s,U) context check
14 * last consonant check and conversion (b, c, d, ğ to p, ç, t, k)
16 * The stemming algorithm is based on the paper "An Affix Stripping
17 * Morphological Analyzer for Turkish" by Gülşen Eryiğit and
18 * Eşref Adalı (Proceedings of the IAESTED International Conference
19 * ARTIFICIAL INTELLIGENCE AND APPLICATIONS, February 16-18,2004,
22 * Turkish is an agglutinative language and has a very rich morphological
23 * structure. In Turkish, you can form many different words from a single stem
24 * by appending a sequence of suffixes. Eg. The word "doktoruymuşsunuz" means
25 * "You had been the doctor of him". The stem of the word is "doktor" and it
26 * takes three different suffixes -sU, -ymUs, and -sUnUz. The rules about
27 * the append order of suffixes can be clearly described as FSMs.
28 * The paper referenced above defines some FSMs for right to left
29 * morphological analysis. I generated a method for constructing snowball
30 * expressions from right to left FSMs for stemming suffixes.
34 append_U_to_stems_ending_with_d_or_g // for preventing some overstemmings
35 check_vowel_harmony // tests vowel harmony for suffixes
36 is_reserved_word // tests whether current string is a reserved word ('ad','soyad')
37 mark_cAsInA // nominal verb suffix
38 mark_DA // noun suffix
39 mark_DAn // noun suffix
40 mark_DUr // nominal verb suffix
41 mark_ki // noun suffix
42 mark_lAr // noun suffix, nominal verb suffix
43 mark_lArI // noun suffix
44 mark_nA // noun suffix
45 mark_ncA // noun suffix
46 mark_ndA // noun suffix
47 mark_ndAn // noun suffix
48 mark_nU // noun suffix
49 mark_nUn // noun suffix
50 mark_nUz // nominal verb suffix
51 mark_sU // noun suffix
52 mark_sUn // nominal verb suffix
53 mark_sUnUz // nominal verb suffix
54 mark_possessives // -(U)m,-(U)n,-(U)mUz,-(U)nUz,
55 mark_yA // noun suffix
56 mark_ylA // noun suffix
57 mark_yU // noun suffix
58 mark_yUm // nominal verb suffix
59 mark_yUz // nominal verb suffix
60 mark_yDU // nominal verb suffix
61 mark_yken // nominal verb suffix
62 mark_ymUs_ // nominal verb suffix
63 mark_ysA // nominal verb suffix
65 mark_suffix_with_optional_y_consonant
66 mark_suffix_with_optional_U_vowel
67 mark_suffix_with_optional_n_consonant
68 mark_suffix_with_optional_s_consonant
70 more_than_one_syllable_word
72 post_process_last_consonants
75 stem_nominal_verb_suffixes
77 stem_suffix_chain_before_ki
82 /* Special characters in Unicode Latin-1 and Latin Extended-A */
83 stringdef c, '{U+00E7}' // LATIN SMALL LETTER C WITH CEDILLA
84 stringdef g~ '{U+011F}' // LATIN SMALL LETTER G WITH BREVE
85 stringdef i' '{U+0131}' // LATIN SMALL LETTER I WITHOUT DOT
86 stringdef o" '{U+00F6}' // LATIN SMALL LETTER O WITH DIAERESIS
87 stringdef s, '{U+015F}' // LATIN SMALL LETTER S WITH CEDILLA
88 stringdef u" '{U+00FC}' // LATIN SMALL LETTER U WITH DIAERESIS
90 booleans ( continue_stemming_noun_suffixes )
92 groupings ( vowel U vowel1 vowel2 vowel3 vowel4 vowel5 vowel6)
94 define vowel 'ae{i'}io{o"}u{u"}'
97 // the vowel grouping definitions below are used for checking vowel harmony
98 define vowel1 'a{i'}ou' // vowels that can end with suffixes containing 'a'
99 define vowel2 'ei{o"}{u"}' // vowels that can end with suffixes containing 'e'
100 define vowel3 'a{i'}' // vowels that can end with suffixes containing 'i''
101 define vowel4 'ei' // vowels that can end with suffixes containing 'i'
102 define vowel5 'ou' // vowels that can end with suffixes containing 'o' or 'u'
103 define vowel6 '{o"}{u"}' // vowels that can end with suffixes containing 'o"' or 'u"'
108 // checks vowel harmony for possible suffixes,
109 // helps to detect whether the candidate for suffix applies to vowel harmony
110 // this rule is added to prevent over stemming
111 define check_vowel_harmony as (
114 (goto vowel) // if there is a vowel
118 ('{i'}' goto vowel3) or
121 ('{o"}' goto vowel6) or
128 // if the last consonant before suffix is vowel and n then advance and delete
129 // if the last consonant before suffix is non vowel and n do nothing
130 // if the last consonant before suffix is not n then only delete the suffix
131 // assumption: slice beginning is set correctly
132 define mark_suffix_with_optional_n_consonant as (
135 ((not(test 'n')) test(next vowel))
139 // if the last consonant before suffix is vowel and s then advance and delete
140 // if the last consonant before suffix is non vowel and s do nothing
141 // if the last consonant before suffix is not s then only delete the suffix
142 // assumption: slice beginning is set correctly
143 define mark_suffix_with_optional_s_consonant as (
146 ((not(test 's')) test(next vowel))
149 // if the last consonant before suffix is vowel and y then advance and delete
150 // if the last consonant before suffix is non vowel and y do nothing
151 // if the last consonant before suffix is not y then only delete the suffix
152 // assumption: slice beginning is set correctly
153 define mark_suffix_with_optional_y_consonant as (
156 ((not(test 'y')) test(next vowel))
159 define mark_suffix_with_optional_U_vowel as (
162 ((not(test U)) test(next non-vowel))
166 define mark_possessives as (
167 among ('m{i'}z' 'miz' 'muz' 'm{u"}z'
168 'n{i'}z' 'niz' 'nuz' 'n{u"}z' 'm' 'n')
169 (mark_suffix_with_optional_U_vowel)
175 (mark_suffix_with_optional_s_consonant)
178 define mark_lArI as (
179 among ('leri' 'lar{i'}')
185 (mark_suffix_with_optional_y_consonant)
190 among ('n{i'}' 'ni' 'nu' 'n{u"}')
195 among ('{i'}n' 'in' 'un' '{u"}n')
196 (mark_suffix_with_optional_n_consonant)
202 (mark_suffix_with_optional_y_consonant)
212 among('da' 'de' 'ta' 'te')
222 among('dan' 'den' 'tan' 'ten')
225 define mark_ndAn as (
233 (mark_suffix_with_optional_y_consonant)
243 (mark_suffix_with_optional_n_consonant)
248 among ('{i'}m' 'im' 'um' '{u"}m')
249 (mark_suffix_with_optional_y_consonant)
254 among ('s{i'}n' 'sin' 'sun' 's{u"}n' )
259 among ('{i'}z' 'iz' 'uz' '{u"}z')
260 (mark_suffix_with_optional_y_consonant)
263 define mark_sUnUz as (
264 among ('s{i'}n{i'}z' 'siniz' 'sunuz' 's{u"}n{u"}z')
274 among ('n{i'}z' 'niz' 'nuz' 'n{u"}z')
279 among ('t{i'}r' 'tir' 'tur' 't{u"}r' 'd{i'}r' 'dir' 'dur' 'd{u"}r')
282 define mark_cAsInA as (
283 among ('cas{i'}na' 'cesine')
288 among ('t{i'}m' 'tim' 'tum' 't{u"}m' 'd{i'}m' 'dim' 'dum' 'd{u"}m'
289 't{i'}n' 'tin' 'tun' 't{u"}n' 'd{i'}n' 'din' 'dun' 'd{u"}n'
290 't{i'}k' 'tik' 'tuk' 't{u"}k' 'd{i'}k' 'dik' 'duk' 'd{u"}k'
291 't{i'}' 'ti' 'tu' 't{u"}' 'd{i'}' 'di' 'du' 'd{u"}')
292 (mark_suffix_with_optional_y_consonant)
295 // does not fully obey vowel harmony
297 among ('sam' 'san' 'sak' 'sem' 'sen' 'sek' 'sa' 'se')
298 (mark_suffix_with_optional_y_consonant)
301 define mark_ymUs_ as (
303 among ('m{i'}{s,}' 'mi{s,}' 'mu{s,}' 'm{u"}{s,}')
304 (mark_suffix_with_optional_y_consonant)
307 define mark_yken as (
308 'ken' (mark_suffix_with_optional_y_consonant)
311 define stem_nominal_verb_suffixes as (
313 set continue_stemming_noun_suffixes
314 (mark_ymUs_ or mark_yDU or mark_ysA or mark_yken)
316 (mark_cAsInA (mark_sUnUz or mark_lAr or mark_yUm or mark_sUn or mark_yUz or true) mark_ymUs_)
319 mark_lAr ] delete try([(mark_DUr or mark_yDU or mark_ysA or mark_ymUs_))
320 unset continue_stemming_noun_suffixes
323 (mark_nUz (mark_yDU or mark_ysA))
325 ((mark_sUnUz or mark_yUz or mark_sUn or mark_yUm) ] delete try([ mark_ymUs_))
327 (mark_DUr ] delete try([ (mark_sUnUz or mark_lAr or mark_yUm or mark_sUn or mark_yUz or true) mark_ymUs_))
331 // stems noun suffix chains ending with -ki
332 define stem_suffix_chain_before_ki as (
336 (mark_DA] delete try([
337 (mark_lAr] delete try(stem_suffix_chain_before_ki))
339 (mark_possessives] delete try([mark_lAr] delete stem_suffix_chain_before_ki))
343 (mark_nUn] delete try([
346 ([mark_possessives or mark_sU] delete try([mark_lAr] delete stem_suffix_chain_before_ki))
348 (stem_suffix_chain_before_ki)
354 ((mark_sU] delete try([mark_lAr]delete stem_suffix_chain_before_ki)))
356 (stem_suffix_chain_before_ki)
361 define stem_noun_suffixes as (
362 ([mark_lAr] delete try(stem_suffix_chain_before_ki))
368 ([mark_possessives or mark_sU] delete try([mark_lAr] delete stem_suffix_chain_before_ki))
370 ([mark_lAr] delete stem_suffix_chain_before_ki)
374 ([(mark_ndA or mark_nA)
378 (mark_sU] delete try([mark_lAr] delete stem_suffix_chain_before_ki))
380 (stem_suffix_chain_before_ki)
384 ([(mark_ndAn or mark_nU) ((mark_sU ] delete try([mark_lAr] delete stem_suffix_chain_before_ki)) or (mark_lArI)))
386 ( [mark_DAn] delete try ([
388 (mark_possessives ] delete try([mark_lAr] delete stem_suffix_chain_before_ki))
390 (mark_lAr] delete try(stem_suffix_chain_before_ki))
392 (stem_suffix_chain_before_ki)
396 ([mark_nUn or mark_ylA] delete
398 ([mark_lAr] delete stem_suffix_chain_before_ki)
400 ([mark_possessives or mark_sU] delete try([mark_lAr] delete stem_suffix_chain_before_ki))
402 stem_suffix_chain_before_ki
408 (stem_suffix_chain_before_ki)
410 ([mark_DA or mark_yU or mark_yA] delete try([((mark_possessives] delete try([mark_lAr)) or mark_lAr) ] delete [ stem_suffix_chain_before_ki))
412 ([mark_possessives or mark_sU] delete try([mark_lAr] delete stem_suffix_chain_before_ki))
415 define post_process_last_consonants as (
424 // after stemming if the word ends with 'd' or 'g' most probably last U is overstemmed
425 // like in 'kedim' -> 'ked'
426 // Turkish words don't usually end with 'd' or 'g'
427 // some very well known words are ignored (like 'ad' 'soyad'
428 // appends U to stems ending with d or g, decides which vowel to add
429 // based on the last vowel in the stem
430 define append_U_to_stems_ending_with_d_or_g as (
432 (test((goto vowel) 'a' or '{i'}') <+ '{i'}')
434 (test((goto vowel) 'e' or 'i') <+ 'i')
436 (test((goto vowel) 'o' or 'u') <+ 'u')
438 (test((goto vowel) '{o"}' or '{u"}') <+ '{u"}')
441 define is_reserved_word as (
442 'ad' try 'soy' atlimit
446 // Tests if there are more than one syllables
447 // In Turkish each vowel indicates a distinct syllable
448 define more_than_one_syllable_word as (
449 test (atleast 2 (gopast vowel))
454 not(is_reserved_word)
455 do append_U_to_stems_ending_with_d_or_g
456 do post_process_last_consonants
462 (more_than_one_syllable_word)
465 do stem_nominal_verb_suffixes
466 continue_stemming_noun_suffixes
467 do stem_noun_suffixes