Выделение основы слова. Стеммер Портера

Привет!
Сегодня, я расскажу про стемминг и его применение.

Что такое стемминг?
Стемминг - это процесс нахождения основы слова. Например, для слова "приставка" основой будет "приставк", а корнем слова "став".

Далее... Зачем нужен стемминг?
Обычно в простых поисковых системах, в которых не требуется учет морфологии, применяется стемминг для обобщения пользовательских запросов.
В этих поисковых системах документы разбиваются на множества основ слов.
Поиск осуществляется по основам слова.

Реализация алгоритма стемминга на C#
  1. using System.Text.RegularExpressions;  
  2. using System;  
  3. namespace Stemmer.RU  
  4. {  
  5.     /// <summary>  
  6.     /// Stemmer  
  7.     /// </summary>  
  8.     class Porter  
  9.     {  
  10.   
  11.         public const string VERSION             = "0.2";  
  12.   
  13.         private const string VOWEL              = "аеиоуыэюя";  
  14.   
  15.         private const string PERFECTIVEGROUND   = "((ив|ивши|ившись|ыв|ывши|ывшись)|((?<=[ая])(в|вши|вшись)))$";  
  16.   
  17.         private const string REFLEXIVE          = "(с[яь])$";  
  18.   
  19.         private const string ADJECTIVE          = "(ее|ие|ые|ое|ими|ыми|ей|ий|ый|ой|ем|им|ым|ом|его|ого|еых|ую|юю|ая|яя|ою|ею)$";  
  20.   
  21.         private const string PARTICIPLE         = "((ивш|ывш|ующ)|((?<=[ая])(ем|нн|вш|ющ|щ)))$";  
  22.   
  23.         private const string VERB               = "((ила|ыла|ена|ейте|уйте|ите|или|ыли|ей|уй|ил|ыл|им|ым|ены|ить|ыть|ишь|ую|ю)|((?<=[ая])(ла|на|ете|йте|ли|й|л|ем|н|ло|но|ет|ют|ны|ть|ешь|нно)))$";  
  24.   
  25.         private const string NOUN               = "(а|ев|ов|ие|ье|е|иями|ями|ами|еи|ии|и|ией|ей|ой|ий|й|и|ы|ь|ию|ью|ю|ия|ья|я)$";  
  26.   
  27.         private const string RVRE               = "^(.*?[аеиоуыэюя])(.*)$";  
  28.   
  29.         private const string DERIVATIONAL       = "[^аеиоуыэюя][аеиоуыэюя]+[^аеиоуыэюя]+[аеиоуыэюя].*(?<=о)сть?$";  
  30.   
  31.         private const string SUPERLATIVE        = "(ейше|ейш)?";  
  32.           
  33.         /// <summary>  
  34.         /// Parses stemm of the word  
  35.         /// </summary>  
  36.         /// <param name="word"></param>  
  37.         /// <returns>Stemm of the word</returns>  
  38.         public string Stemm(string word)  
  39.         {  
  40.             word = word.ToLower();  
  41.             word = word.Replace("ё""е");  
  42.             if (IsMatch(word, RVRE))  
  43.             {  
  44.                 // Step 1  
  45.                 if (!Replace(ref word, PERFECTIVEGROUND, "")) {  
  46.                     Replace(ref word, REFLEXIVE, "");  
  47.                     if (Replace(ref word, ADJECTIVE, "")) {  
  48.                         Replace(ref word, PARTICIPLE, "");  
  49.                     }  
  50.                     else {  
  51.                         if (!Replace(ref word, VERB, "")) {  
  52.                             Replace(ref word, NOUN, "");  
  53.                         }  
  54.   
  55.                     }  
  56.   
  57.                 }  
  58.   
  59.                 // Step 2  
  60.                 Replace(ref word, "и$""");  
  61.   
  62.                 // Step 3  
  63.                 if (IsMatch(word, DERIVATIONAL)) {  
  64.                     Replace(ref word, "ость?$""");  
  65.                 }  
  66.   
  67.                 // Step 4  
  68.                 if (!Replace(ref word, "ь$""")) {  
  69.                     Replace(ref word, SUPERLATIVE, "");  
  70.                     Replace(ref word, "нн$""н");  
  71.                 }  
  72.   
  73.             }  
  74.   
  75.             return word;  
  76.         }  
  77.   
  78.         private bool IsMatch(string word, string matchingPattern)  
  79.         {  
  80.             return new Regex(matchingPattern).IsMatch(word);  
  81.         }  
  82.   
  83.         private bool Replace(ref string replace, string cleaningPattern, string by)   
  84.         {  
  85.             string original = replace;  
  86.             replace = new Regex(cleaningPattern,  
  87.                         RegexOptions.ExplicitCapture|   
  88.                         RegexOptions.Singleline  
  89.                         ).Replace(replace, by);  
  90.             return original != replace;  
  91.         }  
  92.   
  93.     }  
  94.   
  95. }  
Применение стеммера
  1. using System;  
  2. using Stemmer.RU;  
  3. namespace Stemmer  
  4. {  
  5.     class Program  
  6.     {  
  7.         static void Main(string[] args)  
  8.         {  
  9.             Porter p = new Porter();  
  10.             while (true) {  
  11.                 Console.WriteLine("Введите слово:");  
  12.                 string input = Console.ReadLine();  
  13.                 if (input != "выйти") {  
  14.                     Console.WriteLine("Основа слова \"" + input + "\": " + p.Stem(input));  
  15.                 }  
  16.                 else {  
  17.                     break;  
  18.                 }  
  19.                   
  20.             }   
  21.   
  22.         }  
  23.   
  24.     }  
  25.   
  26. }  
Источники
Стемминг
Russian stemming algorithm
Эвристическое (без словаря) извлечение корня из русского слова
Вероятностный морфологический анализатор русского и украинского языков

3 Responses to "Выделение основы слова. Стеммер Портера"

Ернат Асанов Says :
17 ноября 2009 г. в 02:18

Выявлен баг. Класс неправильно выделяет основу слова.

Philip Says :
14 января 2016 г. в 17:42

Спасибо за стеммер! Очень выручили!

Отправить комментарий