crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в разбиение слова на слоги
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
balbes Дата 14.9.2015, 10:19
 
"Код по разбиению слов на слоги, правда на С\С++"
#include <string.h>
#include "macro.h"
//---------------------------------------------------------------------------
  /* EDITOR GLOBALS  */
  
extern  int     left;           // left border (1..78)
extern  int     right;          // right border (2..79)
//---------------------------------------------------------------------------
  /* LINE GLOBALS    */
extern  int     prev;           // previous str real size (= length previous str)
extern  int     is_red;         // indicator: if red-line str
extern  int     last;           // previus word end
extern  int     word_cnt;       // words count in str
extern  int     len;            // real str length
extern  int     found;          // indicator: if in word    
//---------------------------------------------------------------------------
char ANSI_to_ASCII(char sym)  // ANSI(Windows) -> ASCII(DOS)
{
    if((sym >= 'А') && (sym <= 'п'))
      sym -= 64;
    else if((sym >= 'р') && (sym <= 'я'))
      sym -= 16;
   return sym;
}
//---------------------------------------------------------------------------
char ASCII_to_ANSI(unsigned char sym)  // ASCII(DOS) ->  ANSI(Windows)
{
    if((sym >= 128) && (sym <= 175))
      sym += 64;
    else if((sym >= 224) && (sym <= 239))
      sym += 16;
   return sym;
}
//---------------------------------------------------------------------------
void get_ASCII_line(char* str)    // ANSI-str  -> ASCII-str
{
   while(*str)
   {
     *str = ANSI_to_ASCII(*str);
     str++;
   }
   return;
}
//---------------------------------------------------------------------------
int glasn(int sym)    // return 1 - if glasn, else return 0
{
   if((sym == 'а') ||(sym == 'А') ||(sym == 'Е') ||(sym == 'е') ||(sym == 'Ё') ||
      (sym == 'ё') ||(sym == 'И') ||(sym == 'и') ||(sym == 'О') ||(sym == 'о') ||
      (sym == 'У') ||(sym == 'у') ||(sym == 'ы') ||(sym == 'Э') ||(sym == 'э') ||
      (sym == 'Ю') ||(sym == 'ю') ||(sym == 'Я') ||(sym == 'я'))
      return 1;
    else
      return 0;
}
//---------------------------------------------------------------------------
int is_rus_letter(int sym)     // if symbol from russian alphabet
{
   if((sym >= 'А') && (sym <= 'я'))
     return 1;
   else
     return 0;
}
//---------------------------------------------------------------------------
int soglasn(int sym)   // return 1 - if soglasn, else return 0
{  
   if(is_rus_letter(sym) && (!glasn(sym)))
     return 1;
   else
     return 0;  
}
//---------------------------------------------------------------------------
// if any visible symbol not BACKSPACE, GAP, ENTER
int rus_graph(int sym)
{
   if(is_rus_letter(sym) || (sym >= 0x21 && sym <= 0x7E))
     return 1;
   else
     return 0;
}
//---------------------------------------------------------------------------
// return 1 - if there is glasn in str else return 0
int find_glasn(char* str)
{
   while(*str)
   {
      if(glasn(*str))
        return 1;
      else if(!is_rus_letter(*str))
        return 0;
      str++;
   }
   return 0;
}
//---------------------------------------------------------------------------
void get_lower(char* str)     // str -> lower register
{
   while(*str)
   {
      if((*str >= 'А') && (*str <= 'Я'))
        *str += 32;
      str++;
   }
   return;
}
//---------------------------------------------------------------------------
// binary search: return first word index with first letter sym, kol - words_count
// else: return -1
int bs(char sym, char** mas, int kol)
{
  int  x, l, r;
  r = kol - 1;                 // right member
  l = 0;                       // left member
  while(l < r)
  {
    x = (r + l) / 2;           // choose middle member
    if(mas[x][0] >= sym)
      r = x;
    else
      l = x + 1;
  }
  if(mas[l][0] == sym)
    return l;
  else
    return -1;
}
//---------------------------------------------------------------------------
// separate prefix, return index of next word part after prefix or 0
int get_pref(char* str)
{
    int   i = 0;        // index in str
    int   len = 0;            // prefix length
    int   n;            // str length
    char* pref_list[] = {"без", "беc", "воз", "вос", "дез", "за", "из", "ис", "контр",
                         "меж", "на", "не", "низ", "нис", "обо", "об", "пан", "пол",
                         "пост", "под", "по", "пред", "пре", "при", "раз", "рас",
                         "рос", "сверх", "со", "суб", "транс", "чрез", "чрес" };
    // at first largest prefixes, for example, "под", "по"
    char* curr_pref;        // current prefix
    char  temp_str[MAXSTR]; // to duplicate str
    int   found = FALSE;    // found = TRUE - prefix found
    int   pref_count = sizeof(pref_list) / sizeof(char*);
    n = strlen(str);
    strcpy(temp_str, str);                   // store str in temp_str
    i = bs(str[0], pref_list, pref_count);   // first letter prefix
    if(i == -1)                              // not found first letter
    {
      strcpy(str, temp_str);                 //restore str
      return 0;
    }
    do
    {
      curr_pref = pref_list[i];            // get new prefix
      // cmp with mask of next prefix
      if(!(strncmp(curr_pref, str, strlen(curr_pref))))
      {
        found = TRUE;
        break;
      }
      i++;
    }
    while((i < pref_count) && (pref_list[i][0] == str[0]));
    // while not end of pref_list and prefix begins from the same letter
    if(found == FALSE)
    {
      strncpy(str, temp_str, n);             //restore str
      return 0;
    }
    len = strlen(curr_pref);                 // get prefix length
    // example: "подъ-езд" , "пой-ти" -> increase len
     if((str[len] == 'ъ') || ((str[len] == 'й') && glasn(str[len - 1])))
      len++;
    //  if prefix ends with soglasn nd next letter "ы", example: "ра-зыграть"
    //  "раз-ыграть"  - error
    // -> decrease len
    else
    {                                        // "об-ыскать"  - error
      if((str[len] == 'ы') && soglasn(str[len - 1]) && len > 2)
        len--;                               // "по-дыскать"
      else if((str[len] == 'ы') && soglasn(str[len - 1]) && len <= 2)
        len = 0;                             // "о-быскать"  - error
    }
    strcpy(str, temp_str);                  //restore str
    return len;
}
//---------------------------------------------------------------------------
/* return 0 - if position i is not valid for perenos
  else return valid perenos index
  str - word, i - index for checking, rpos - max vlid index for perenos
*/
int rule_gl(char* str, int i, int rpos)
{
       int  k, j;
       int  pos;
       pos = k = j = 0;
       if(str[i + 1] == 'й')
         j = 1;           // glasn + 'й' = one letter
       if((str[i - 1] == 'ъ') ||(str[i - 1] == 'ь'))
           k = 1;           // soglasn + 'ъ' = one letter
// if next letter - glasn, prev letter - soglasn, at least 2 letters after possible perenos
       if(glasn(str[i + j + 1]) && soglasn(str[i - k - 1]) &&
         is_rus_letter(str[i + j + 2]))
       {
         pos = (pos > rpos) ? 0 : (i + j);
       }
// if next letter - soglasn, prev letter - glasn, there is at least one glasn in rpart
       else if(soglasn(str[i + j + 1]) && soglasn(str[i - k - 1]) && find_glasn(str + i + j + 2))
       {
         pos = (pos > rpos) ? 0 : (i + j);
       }
        
       return pos;
}
//---------------------------------------------------------------------------
/* return 0 - if position i is not valid for perenos
  else return valid perenos index
  str - word, i - index for checking, rpos - max vlid index for perenos
*/
int rule_sogl(char* str, int i, int rpos)
{
       int  j;
       int  pos = 0;
       pos = j = 0;
       if((str[i + 1] == 'ъ') ||(str[i + 1] == 'ь'))
         j = 1;  // soglasn + 'ъ' = one letter
// if next letter - soglasn, prev letter - glasn, there is at least one glasn in rpart
       if(soglasn(str[i + j + 1]) && glasn(str[i - 1]) &&
         find_glasn(str + i + j + 2))
       {
           pos = (pos > rpos) ? 0 : (i + j);
       }
       return pos;
}
//---------------------------------------------------------------------------
// rpos - max right perenos position, lpart - left_str + '-', rpart - right_str
void get_perenos(char* str, int rpos, char* lpart, char* rpart)
{
    int   len;
    int   t = 0;         // word part after non-letter symbols - (, " e.t.c.
    int   st = 0;        // word part after prefix
    int   i;             // current str index
    int   pos = 0;       // found perenos position
    int   max = FALSE;   // indicator: if maxlen str without perenos
    char  temp[MAXSTR];  // to duplicate str
    if(rpos <= 1)        // if there is space for only letter - > impossible
    {
      *lpart = '\0';
      strcpy(rpart, str);
      return;
    }
    strcpy(temp, str);                       // store str
    get_lower(str);                          // get str in lower register
    while(str[t] && !is_rus_letter(str[t]))  // missing non-letter symbols
    {
      t++;                                   // count of non-letter symbols
      str++;                                 // cut str beginning
    }
    if((*str == '\0') || (t >= rpos))        // if all str consists of non-letter symbols
    {                                        // or letters are too far to get perenos
      *lpart = '\0';
      strcpy(rpart, temp);                   // impossible
      return;
    }
    rpos -= t;                              // correction rpos for new str
    len = strlen(str);                      // str length
    st = get_pref(str);                     // try to get prefix
    if(st > rpos)             // if no enough space to get perenos of one_slog prefix
    {                         // we need 1 position for '-'
      *lpart = '\0';
      strcpy(rpart, temp);    // impossible
      return;
    }
    i = (rpos > (len - 3)) ? (len - 3) : rpos;
    // set max possible i index for perenos (at least 2 letters must be for right)
    // or pred-pred last letter, or rpos
    while(i > st)           // try to get perenos after prefix
    {
       if(glasn(str[i]))
       {
         if(pos = rule_gl(str, i, rpos))
           break;
       }
       else if(soglasn(str[i]))
       {
         if(pos = rule_sogl(str, i, rpos))
           break;
       }
       i--;    // take prev position to try get perenos
    }
    // after cycle:
    // if found prefix and no perenos after prefix and
    // 1) only one letter after prefix   or
    // 2) no glasn in rpart
    if(!pos && st && (((len - st) == 1) || !(find_glasn(str + st))))
    {
      *lpart = '\0';            // impossible
      strcpy(rpart, temp);
      return;
    }
    // if no prefix and no perenos
    if(!pos && !st)
    {
      if((len < (right - left + 1 - is_red - t)))  // if not the whole str without perenos
      {
        *lpart = '\0';
        strcpy(rpart, temp);
        return;
      }
      else
      {
        pos = len - 2;        // if "ппппппппппппппппп"  (only soglasn without glasn)
        max = TRUE;
      }
    }
    // if 1) found prefix
    //    2) no perenos after prefix
    //    3) rpart  - not one letter
    //    4) first glasn after prefix  - Ы
    if(!pos && st && ((len - st) > 1))
      if(str[st] == 'ы')
        pos = st - 2;               // "по-дытожить"
      else
        pos = st - 1;                   // "под-ставить"
    pos += t;                       // return folowwing non-letter symbols
    strncpy(lpart, temp, pos + 1);  // fill lpart
    if(!max)                        // if not the whole str without perenos
    {
      lpart[pos + 1] = '-';         // add '-'
      lpart[pos + 2] = '\0';
    }
    else
      lpart[pos + 1] = '\0';        // without '-'
    strcpy(rpart, temp + pos + 1);  // fill rpart
    return;
}
Iron Bug Дата 30.8.2015, 18:54
  думаю, что в библиотеку такой функционал не влезет. слог - понятие слишком абстрактное. более того, лингвисты не имеют точного определения для слога и в ритмическом понятии слога, например, одно слово может иметь разное количество слогов в разных сочетаниях с другими словами. строго говоря, надо собрать в базе все возможные варианты слогов и перебирать их нетривиальным образом, ещё и учитывая окружение. а если ещё и для разных языков, у каждого из которых свои тараканы, то это гигантский объём данных и сложные алгоритмы их обработки.
romanick Дата 30.8.2015, 12:15
  У кого-нибудь есть кусок кода Qt, разбивающий слова по слогам? Или может быть библиотеку какую-нибудь кто подскажет? Интересует не только русский.
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 28.3.2024, 11:46