#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
The Snowball stemmer.
"""
import re
import unittest
class Stemmer:
# Helper regex strings.
_vowel = "[аәоөұүыіеиуёэюя]"
_non_vowel = "[^аәоөұүыіеиуёэюя]"
# Word regions.
_re_rv = re.compile(_vowel)
_re_r1 = re.compile(_vowel + _non_vowel)
# Endings.
_re_all = re.compile(
r"(шалық|шелік|даған|деген|таған|теген|лаған|леген|"
r"дайын|дейін|тайын|тейін|"
r"ңдар|ңдер|дікі|тікі|нікі|атын|етін|йтын|йтін|"
r"гелі|қалы|келі|ғалы|шама|шеме|"
r"мын|мін|бын|бін|пын|пін|мыз|міз|быз|біз|пыз|піз|сың|сің|"
r"сыз|сіз|ңыз|ңіз|дан|ден|тан|тен|нан|нен|нда|нде|дың|дің|тың|"
r"тің|ның|нің|дар|дер|тар|тер|лар|лер|бен|пен|мен|"
r"дай|дей|тай|тей|дық|дік|тық|тік|лық|лік|паз|"
r"ғыш|гіш|қыш|кіш|шек|шақ|шыл|шіл|нші|ншы|дап|деп|"
r"тап|теп|лап|леп|даc|деc|таc|теc|лаc|леc|ғар|гер|қар|кер|дыр|"
r"дір|тыр|тір|ғыз|гіз|қыз|кіз|ған|ген|қан|кен|"
r"ушы|уші|лай|лей|сын|сін|бақ|бек|пақ|пек|мақ|мек|йын|йін|йық|йік|"
r"сы|сі|да|де|та|те|ға|ге|қа|ке|на|не|"
r"ді|ты|ті|ны|ні|ды|ба|бе|па|пе|ма|ме|"
r"лы|лі|ғы|гі|қы|кі|ау|еу|ла|ле|ар|ер|"
r"ып|іп|ша|ше|са|се|"
r"лақ|лық|"
r"н|р|п|й|ы|і)$"
)
def stem(self, word):
"""
Gets the stem.
"""
rv_pos, r2_pos = self._find_rv(word), self._find_r2(word)
word1 = self._step_1(word, r2_pos)
while word1 != word:
word = word1
word1 = self._step_1(word, r2_pos)
return word1
def _find_rv(self, word):
"""
Searches for the RV region.
"""
rv_match = self._re_rv.search(word)
if not rv_match:
return len(word)
return rv_match.end()
def _find_r2(self, word):
"""
Searches for the R2 region.
"""
r1_match = self._re_r1.search(word)
if not r1_match:
return len(word)
r2_match = self._re_r1.search(word, r1_match.end())
if not r2_match:
return len(word)
return r2_match.end()
def _cut(self, word, ending, pos):
"""
Tries to cut the specified ending after the specified position.
"""
match = ending.search(word, pos)
if match:
try:
ignore = match.group("ignore") or ""
except IndexError:
# No ignored characters in pattern.
return True, word[:match.start()]
else:
# Do not cut ignored part.
return True, word[:match.start() + len(ignore)]
else:
return False, word
def _step_1(self, word, r_pos):
_, word = self._cut(word, self._re_all, r_pos)
return word
class TestStemmer(unittest.TestCase):
"""
Tests the stemmer.
"""
_stemmer = Stemmer()
def test_stem(self):
with open("diffs-kazak.txt", "rt", encoding="utf-8") as diffs_file:
diffs = diffs_file.readlines()
for i, line in enumerate(diffs):
word, stem = line.split()
self.assertEqual(
stem,
self._stemmer.stem(word),
"Diff in word: %s (%d/%d)" % (word, i + 1, len(diffs)),
)
if __name__ == "__main__":
""""
unittest.main()
"""
stemmer = Stemmer()
word = "Слово"
word = stemmer.stem(word)
print(word)