Как определить все места в слове, в которых можно осуществить перенос части этого слова на другую строку, по правилам русского языка?

Здравствуйте.

Есть некоторое произвольное русскоязычное слово, к примеру:
Интернационализация
Это слово, по правилам русского языка, можно переносить по следующим слогам:
Ин-тер-наци-она-лиза-ция - по крайней мере так Word переносит.
То есть переносы в данном слове можно осуществлять в 5-ти местах.

Мне необходимо автоматически определять в каких местах некоторого русскоязычного слова можно осуществлять перенос (части слова на другую строку по правилам русского языка). То есть определять после какой буквы по счету, с самого начала слова, можно осуществлять перенос.

Как это можно реализовать?

P.S. Может существуют для этого какие-либо готовые инструменты, к примеру в библиотеке .NET, или в какой-либо сторонней библиотеке?
  • Вопрос задан
  • 1125 просмотров
Решения вопроса 2
@ERAFY Автор вопроса
В общем у меня получился нижеприведенный класс, позволяющий расставлять знаки "тире" в местах переноса слов по правилам русского языка.
Класс работает на основе алгоритма Христова, и написан на языке C#.

Запускать на выполнение нижеприведенный код можно строкой:
word = PasteDashes.SeparateWord(word);
Возможно кому пригодиться в будущем.

-------------------------------------------------------

public static class PasteDashes
    {
        // Метод проверки, есть ли в строке гласные?
        private static bool isNotLastSep(string subStr)
        {
            string vowel = "аеёиоуыэюя";

            var b = false;
            for (var i = 0; i < subStr.Length; i++)
            {
                if (vowel.IndexOf(subStr.Substring(i, 1)) != -1)
                {
                    b = true;
                    break;
                }
            }
            return b;
        }


        // Метод разбиения слова на слоги
        private static List<string> addSeparator(string tmpS, List<string> sepList)
        {
            sepList.Add(tmpS);
            //tmpS = "";

            return sepList;
        }


        // Метод убирания знаков тире после первой буквы и перед последней (если там есть знаки тире)
        private static string ConnectFirstAndLastLettersToSyllables(string word)
        {
            if (word[1] == '-')
                word = word.Remove(1, 1);

            if (word[word.Length - 2] == '-')
                word = word.Remove(word.Length - 2, 1);

            return word;
        }



        //Основной метод работающий по алгоритму Христова
        public static string SeparateWord(string word)
        {
            string vowel = "аеёиоуыэюя";
            string voiced = "бвгджзлмнрхцчшщ";
            string deaf = "кпстф";
            string brief = "й";
            string other = "ьъ";
            string consonant = "бвгджзйклмнпрстфхцчшщ";

            string letter, syllable = "";
            var syllables = new List<string>();


            for (var i = 0; i < word.Length; i++)
            {
                letter = word.Substring(i, 1);
                syllable += letter;

                bool l;
                if (word.Length != i + 1)
                {
                    var k = word.Substring(i + 1, 1);
                    Regex rgx = new Regex("[А-Яа-я]");
                    l = rgx.IsMatch(k);
                }
                else
                    l = false;


                if (l)
                {
                    // Проверка на признаки конца слогов
                    // Если буква равна 'й' и она не первая и не последняя и это не последний слог
                    if (
                        (i != 0) &&
                        (i != word.Length - 1) &&
                        (brief.IndexOf(letter) != -1) &&
                        (isNotLastSep(word.Substring(i + 1)))
                        )
                    {
                        syllables = addSeparator(syllable, syllables);
                        syllable = "";
                        //continue;
                    }

                    // Если текущая гласная и следующая тоже гласная
                    // EDIT: этот блок необходим если задача - корректно разбить слово на фонетические слоги,
                    // и не нужен если задача - разбить слово на части, которые можно переносить
                    //if (
                    //    (i < word.Length - 1)
                    //    && (vowel.IndexOf(letter) != -1) &&
                    //    (vowel.IndexOf(word.Substring(i + 1, 1)) != -1)
                    //    )
                    //{
                    //    syllables = addSeparator(syllable, syllables);
                    //    syllable = "";
                    //    // continue;
                    //}

                    // Если текущая гласная, следующая согласная, а после неё гласная
                    if (
                        (i < word.Length - 2) &&
                        (vowel.IndexOf(letter) != -1) &&
                        (consonant.IndexOf(word.Substring(i + 1, 1)) != -1) &&
                        (vowel.IndexOf(word.Substring(i + 2, 1)) != -1)
                        )
                    {
                        syllables = addSeparator(syllable, syllables);
                        syllable = "";
                        // continue;
                    }

                    // Если текущая гласная, следующая глухая согласная, а после согласная и это не последний слог
                    if (
                        (i < word.Length - 2) &&
                        (vowel.IndexOf(letter) != -1) &&
                        (deaf.IndexOf(word.Substring(i + 1, 1)) != -1) &&
                        (consonant.IndexOf(word.Substring(i + 2, 1)) != -1) &&
                        (isNotLastSep(word.Substring(i + 1)))
                        )
                    {
                        syllables = addSeparator(syllable, syllables);
                        syllable = "";
                        // continue;
                    }

                    // Если текущая звонкая или шипящая согласная, перед ней гласная, следующая не гласная и не другая, и это не последний слог
                    if (
                        (i > 0) &&
                        (i < word.Length - 1) &&
                        (voiced.IndexOf(letter) != -1) &&
                        (vowel.IndexOf(word.Substring(i - 1, 1)) != -1) &&
                        (vowel.IndexOf(word.Substring(i + 1, 1)) == -1) &&
                        (other.IndexOf(word.Substring(i + 1, 1)) == -1) &&
                        (isNotLastSep(word.Substring(i + 1)))
                        )
                    {
                        syllables = addSeparator(syllable, syllables);
                        syllable = "";
                        // continue;
                    }

                    // Если текущая другая, а следующая не гласная если это первый слог
                    if (
                        (i < word.Length - 1) &&
                        (other.IndexOf(letter) != -1) &&
                        ((vowel.IndexOf(word.Substring(i + 1, 1)) == -1) ||
                        (isNotLastSep(word.Substring(0, i))))
                        )
                    {
                        syllables = addSeparator(syllable, syllables);
                        syllable = "";
                        //continue;
                    }
                }
            }
            syllables = addSeparator(syllable, syllables);

            string finalWord = string.Join("-", syllables);

            finalWord = ConnectFirstAndLastLettersToSyllables(finalWord);

            return finalWord;
        }
    }
Ответ написан
lazalu68
@lazalu68
Salmon
Это конечно не .NET, но вот вам пример реализации на JS:

var vowels = 'оеаиуяыюэё',
    voiced = 'нрвлмдгбзчхжшцщ',
    deaf = 'тскпф',
    brief = 'й',
    other = 'ьъ',
    consonants = 'нтсрвлкмдпгбзчхжшцщф';

function isNotLastSep(remainStr) {
  var is = false;

  for (var i = 0; i < remainStr.length; i++) {
    if (vowels.indexOf(remainStr.substr (i, 1)) != -1) { 
      is = true; 
      break; 
    }
  } 

  return is;
} 

function separate(s) {
  var letter = '',
      syllable = '',
      syllables = [],
      final_syllables = [];

  function pushSyllable() {
    syllables.push(syllable);
    syllable = '';
  };


  for (var i = 0; i < s.length; i++) {
    letter = s.substr (i, 1);
    syllable += letter;

    // Проверка на признаки конца слогов
    // если буква равна 'й' и она не первая и не последняя и это не последний слог
    if (
      (i != 0) && 
      (i != s.length -1) && 
      (brief.indexOf (letter) != -1) &&
      (isNotLastSep (s.substr (i+1, s.length-i+1)))
    ) { pushSyllable (); continue; }

    // если текущая гласная и следующая тоже гласная
    // EDIT: этот блок необходим если задача - корректно разбить слово на фонетические слоги,
    // и не нужен если задача - разбить слово на части, которые можно переносить
    //
    //  if (
    //  (i < s.length - 1) && 
    //  (vowels.indexOf (letter) != -1) && 
    //  (vowels.indexOf (s.substr (i+1, 1)) != -1)
    //) { pushSyllable (); continue; }

    // если текущая гласная, следующая согласная, а после неё гласная
    if (
      (i < s.length - 2) && 
      (vowels.indexOf (letter) != -1) && 
      (consonants.indexOf (s.substr (i+1, 1)) != -1) && 
      (vowels.indexOf (s.substr (i+2, 1)) != -1)
    ) { pushSyllable (); continue; }

    // если текущая гласная, следующая глухая согласная, а после согласная и это не последний слог
    if (
      (i < s.length - 2) && 
      (vowels.indexOf (letter) != -1) && 
      (deaf.indexOf (s.substr (i+1, 1)) != -1) && 
      (consonants.indexOf (s.substr (i+2, 1)) != -1) &&
      (isNotLastSep (s.substr (i+1, s.length-i+1)))
    ) { pushSyllable (); continue; }

    // если текущая звонкая или шипящая согласная, перед ней гласная, следующая не гласная и не другая, и это не последний слог
    if (
      (i > 0) && 
      (i < s.length - 1) && 
      (voiced.indexOf (letter) != -1) && 
      (vowels.indexOf (s.substr (i-1, 1)) != -1) && 
      (vowels.indexOf (s.substr (i+1, 1)) == -1) && 
      (other.indexOf (s.substr (i+1, 1)) == -1) && 
      (isNotLastSep (s.substr (i+1, s.length-i+1)))
    ) { pushSyllable (); continue; }  

    // если текущая другая, а следующая не гласная если это первый слог
    if (
      (i < s.length - 1) && 
      (other.indexOf (letter) != -1) &&
      ((vowels.indexOf (s.substr (i+1, 1)) == -1) || 
      (isNotLastSep (s.substr (0, i))))
    ) { pushSyllable (); continue; } 
  }
  pushSyllable();

  return syllables;
}


То есть чтобы получить слово с &shy; в нужных местах, делаем так:

separate('интернационализация').join('&shy;'); 
// ["ин", "тер", "на", "цио", "на", "ли", "за", "ция"] => "ин&shy;тер&shy;на&shy;цио&shy;на&shy;ли&shy;за&shy;ция"


Взято отсюда, чуть косметически модицифировано.

Кажется, это как раз и есть реализация алгоритма Хpистова:

«Х-»
«Г-Г»
«ГС-СГ»
«СГ-СГ»
«ГС-ССГ»
«ГСС-ССГ»

Где: Г — гласная, С — согласная, Х — буква из набора «ьъй».
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы