portugese.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. from .bases import _StandardStemmer
  2. from whoosh.compat import u
  3. class PortugueseStemmer(_StandardStemmer):
  4. """
  5. The Portuguese Snowball stemmer.
  6. :cvar __vowels: The Portuguese vowels.
  7. :type __vowels: unicode
  8. :cvar __step1_suffixes: Suffixes to be deleted in step 1 of the algorithm.
  9. :type __step1_suffixes: tuple
  10. :cvar __step2_suffixes: Suffixes to be deleted in step 2 of the algorithm.
  11. :type __step2_suffixes: tuple
  12. :cvar __step4_suffixes: Suffixes to be deleted in step 4 of the algorithm.
  13. :type __step4_suffixes: tuple
  14. :note: A detailed description of the Portuguese
  15. stemming algorithm can be found under
  16. http://snowball.tartarus.org/algorithms/portuguese/stemmer.html
  17. """
  18. __vowels = u("aeiou\xE1\xE9\xED\xF3\xFA\xE2\xEA\xF4")
  19. __step1_suffixes = ('amentos', 'imentos', 'uciones', 'amento',
  20. 'imento', 'adoras', 'adores', u('a\xE7o~es'),
  21. u('log\xEDas'), u('\xEAncias'), 'amente',
  22. 'idades', 'ismos', 'istas', 'adora',
  23. u('a\xE7a~o'), 'antes', u('\xE2ncia'),
  24. u('log\xEDa'), u('uci\xF3n'), u('\xEAncia'),
  25. 'mente', 'idade', 'ezas', 'icos', 'icas',
  26. 'ismo', u('\xE1vel'), u('\xEDvel'), 'ista',
  27. 'osos', 'osas', 'ador', 'ante', 'ivas',
  28. 'ivos', 'iras', 'eza', 'ico', 'ica',
  29. 'oso', 'osa', 'iva', 'ivo', 'ira')
  30. __step2_suffixes = (u('ar\xEDamos'), u('er\xEDamos'), u('ir\xEDamos'),
  31. u('\xE1ssemos'), u('\xEAssemos'), u('\xEDssemos'),
  32. u('ar\xEDeis'), u('er\xEDeis'), u('ir\xEDeis'),
  33. u('\xE1sseis'), u('\xE9sseis'), u('\xEDsseis'),
  34. u('\xE1ramos'), u('\xE9ramos'), u('\xEDramos'),
  35. u('\xE1vamos'), 'aremos', 'eremos', 'iremos',
  36. 'ariam', 'eriam', 'iriam', 'assem', 'essem',
  37. 'issem', 'ara~o', 'era~o', 'ira~o', 'arias',
  38. 'erias', 'irias', 'ardes', 'erdes', 'irdes',
  39. 'asses', 'esses', 'isses', 'astes', 'estes',
  40. 'istes', u('\xE1reis'), 'areis', u('\xE9reis'),
  41. 'ereis', u('\xEDreis'), 'ireis', u('\xE1veis'),
  42. u('\xEDamos'), 'armos', 'ermos', 'irmos',
  43. 'aria', 'eria', 'iria', 'asse', 'esse',
  44. 'isse', 'aste', 'este', 'iste', 'arei',
  45. 'erei', 'irei', 'aram', 'eram', 'iram',
  46. 'avam', 'arem', 'erem', 'irem',
  47. 'ando', 'endo', 'indo', 'adas', 'idas',
  48. u('ar\xE1s'), 'aras', u('er\xE1s'), 'eras',
  49. u('ir\xE1s'), 'avas', 'ares', 'eres', 'ires',
  50. u('\xEDeis'), 'ados', 'idos', u('\xE1mos'),
  51. 'amos', 'emos', 'imos', 'iras', 'ada', 'ida',
  52. u('ar\xE1'), 'ara', u('er\xE1'), 'era',
  53. u('ir\xE1'), 'ava', 'iam', 'ado', 'ido',
  54. 'ias', 'ais', 'eis', 'ira', 'ia', 'ei', 'am',
  55. 'em', 'ar', 'er', 'ir', 'as',
  56. 'es', 'is', 'eu', 'iu', 'ou')
  57. __step4_suffixes = ("os", "a", "i", "o", u("\xE1"),
  58. u("\xED"), u("\xF3"))
  59. def stem(self, word):
  60. """
  61. Stem a Portuguese word and return the stemmed form.
  62. :param word: The word that is stemmed.
  63. :type word: str or unicode
  64. :return: The stemmed form.
  65. :rtype: unicode
  66. """
  67. word = word.lower()
  68. step1_success = False
  69. step2_success = False
  70. word = (word.replace(u("\xE3"), "a~")
  71. .replace(u("\xF5"), "o~"))
  72. r1, r2 = self._r1r2_standard(word, self.__vowels)
  73. rv = self._rv_standard(word, self.__vowels)
  74. # STEP 1: Standard suffix removal
  75. for suffix in self.__step1_suffixes:
  76. if word.endswith(suffix):
  77. if suffix == "amente" and r1.endswith(suffix):
  78. step1_success = True
  79. word = word[:-6]
  80. r2 = r2[:-6]
  81. rv = rv[:-6]
  82. if r2.endswith("iv"):
  83. word = word[:-2]
  84. r2 = r2[:-2]
  85. rv = rv[:-2]
  86. if r2.endswith("at"):
  87. word = word[:-2]
  88. rv = rv[:-2]
  89. elif r2.endswith(("os", "ic", "ad")):
  90. word = word[:-2]
  91. rv = rv[:-2]
  92. elif (suffix in ("ira", "iras") and rv.endswith(suffix) and
  93. word[-len(suffix) - 1:-len(suffix)] == "e"):
  94. step1_success = True
  95. word = "".join((word[:-len(suffix)], "ir"))
  96. rv = "".join((rv[:-len(suffix)], "ir"))
  97. elif r2.endswith(suffix):
  98. step1_success = True
  99. if suffix in (u("log\xEDa"), u("log\xEDas")):
  100. word = word[:-2]
  101. rv = rv[:-2]
  102. elif suffix in (u("uci\xF3n"), "uciones"):
  103. word = "".join((word[:-len(suffix)], "u"))
  104. rv = "".join((rv[:-len(suffix)], "u"))
  105. elif suffix in (u("\xEAncia"), u("\xEAncias")):
  106. word = "".join((word[:-len(suffix)], "ente"))
  107. rv = "".join((rv[:-len(suffix)], "ente"))
  108. elif suffix == "mente":
  109. word = word[:-5]
  110. r2 = r2[:-5]
  111. rv = rv[:-5]
  112. if r2.endswith(("ante", "avel", u("\xEDvel"))):
  113. word = word[:-4]
  114. rv = rv[:-4]
  115. elif suffix in ("idade", "idades"):
  116. word = word[:-len(suffix)]
  117. r2 = r2[:-len(suffix)]
  118. rv = rv[:-len(suffix)]
  119. if r2.endswith(("ic", "iv")):
  120. word = word[:-2]
  121. rv = rv[:-2]
  122. elif r2.endswith("abil"):
  123. word = word[:-4]
  124. rv = rv[:-4]
  125. elif suffix in ("iva", "ivo", "ivas", "ivos"):
  126. word = word[:-len(suffix)]
  127. r2 = r2[:-len(suffix)]
  128. rv = rv[:-len(suffix)]
  129. if r2.endswith("at"):
  130. word = word[:-2]
  131. rv = rv[:-2]
  132. else:
  133. word = word[:-len(suffix)]
  134. rv = rv[:-len(suffix)]
  135. break
  136. # STEP 2: Verb suffixes
  137. if not step1_success:
  138. for suffix in self.__step2_suffixes:
  139. if rv.endswith(suffix):
  140. step2_success = True
  141. word = word[:-len(suffix)]
  142. rv = rv[:-len(suffix)]
  143. break
  144. # STEP 3
  145. if step1_success or step2_success:
  146. if rv.endswith("i") and word[-2] == "c":
  147. word = word[:-1]
  148. rv = rv[:-1]
  149. ### STEP 4: Residual suffix
  150. if not step1_success and not step2_success:
  151. for suffix in self.__step4_suffixes:
  152. if rv.endswith(suffix):
  153. word = word[:-len(suffix)]
  154. rv = rv[:-len(suffix)]
  155. break
  156. # STEP 5
  157. if rv.endswith(("e", u("\xE9"), u("\xEA"))):
  158. word = word[:-1]
  159. rv = rv[:-1]
  160. if ((word.endswith("gu") and rv.endswith("u")) or
  161. (word.endswith("ci") and rv.endswith("i"))):
  162. word = word[:-1]
  163. elif word.endswith(u("\xE7")):
  164. word = "".join((word[:-1], "c"))
  165. word = word.replace("a~", u("\xE3")).replace("o~", u("\xF5"))
  166. return word