Обнаружение слогов словом

Мне нужно найти довольно эффективный способ обнаружения слогов одним словом. Например,

Невидимый -> in-vi-sib-le

Существуют правила силлабификации, которые можно использовать:

V CV VC CVC CCV CCCV CVCC

* где V – гласный, а C – согласный. Например,

Произношение (5 Pro-nun-ci-a-tion; CV-CVC-CV-V-CVC)

Я пробовал несколько методов, среди которых использовалось регулярное выражение (которое помогает только в том случае, если вы хотите рассчитать слоги) или определение жесткого кодированного правила (подход грубой силы, который оказывается очень неэффективным) и, наконец, использование автоматов с конечным состоянием (что не результат с чем-либо полезным).

objective моего приложения – создать словарь всех слогов на определенном языке. Этот словарь позже будет использоваться для приложений проверки орфографии (с использованием байесовских classификаторов) и синтеза текста в речь.

Я был бы признателен, если бы вы могли дать мне советы по альтернативному решению этой проблемы, кроме моих предыдущих подходов.

Я работаю на Java, но любой совет в C / C ++, C #, Python, Perl … будет работать для меня.

Читайте о подходе TeX к этой проблеме в целях переноса. Специально см. Диссертацию диссертации Фрэнка Ляна « Слово Hy-phen-a-tion» от Com-put-er . Его алгоритм очень точен, а затем включает небольшой словарь исключений для случаев, когда алгоритм не работает.

Я наткнулся на эту страницу, ища то же самое, и нашел несколько реализаций бумаги Ляна здесь: https://github.com/mnater/hyphenator

То есть, если вы не тот тип, который любит читать 60-страничный тезис вместо того, чтобы адаптировать свободно ansible код для неповторимой проблемы. 🙂

Вот решение, использующее NLTK :

from nltk.corpus import cmudict d = cmudict.dict() def nsyl(word): return [len(list(y for y in x if y[-1].isdigit())) for x in d[word.lower()]] 

Я пытаюсь решить эту проблему для программы, которая будет вычислять оценку чтения flesch-kincaid и flesch блока текста. Мой алгоритм использует то, что я нашел на этом веб-сайте: http://www.howmanysyllables.com/howtocountsyllables.html, и он становится достаточно близким. У него все еще есть проблемы со сложными словами, такими как невидимые и переносы, но я обнаружил, что он попадает на стадион для моих целей.

У этого есть потенциал быть легким в реализации. Я обнаружил, что «es» может быть либо слоговым, либо нет. Это азартная игра, но я решил удалить их в своем алгоритме.

 private int CountSyllables(string word) { char[] vowels = { 'a', 'e', 'i', 'o', 'u', 'y' }; string currentWord = word; int numVowels = 0; bool lastWasVowel = false; foreach (char wc in currentWord) { bool foundVowel = false; foreach (char v in vowels) { //don't count diphthongs if (v == wc && lastWasVowel) { foundVowel = true; lastWasVowel = true; break; } else if (v == wc && !lastWasVowel) { numVowels++; foundVowel = true; lastWasVowel = true; break; } } //if full cycle and no vowel found, set lastWasVowel to false; if (!foundVowel) lastWasVowel = false; } //remove es, it's _usually? silent if (currentWord.Length > 2 && currentWord.Substring(currentWord.Length - 2) == "es") numVowels--; // remove silent e else if (currentWord.Length > 1 && currentWord.Substring(currentWord.Length - 1) == "e") numVowels--; return numVowels; } 

Это особенно сложная проблема, которая не полностью решена алгоритмом переноса переносов LaTeX. Хорошее резюме некоторых доступных методов и связанных с ними проблем можно найти в документе « Оценка алгоритмов автоматической силлабификации для английского языка» (Marchand, Adsett и Damper 2007).

Perl имеет модуль Lingua :: Phonology :: Syllable . Вы можете попробовать это или попробовать изучить его алгоритм. Я видел еще несколько старых модhive.

Я не понимаю, почему регулярное выражение дает вам только количество слогов. Вы должны иметь возможность самим сбивать слоги, используя скобки для захвата. Предполагая, что вы можете построить регулярное выражение, которое работает, то есть.

Спасибо Joe Basirico за то, что вы делитесь своей быстрой и грязной реализацией на C #. Я использовал большие библиотеки, и они работают, но они обычно немного медленны, и для быстрых проектов ваш метод работает нормально.

Вот ваш код на Java, а также тестовые примеры:

 public static int countSyllables(String word) { char[] vowels = { 'a', 'e', 'i', 'o', 'u', 'y' }; char[] currentWord = word.toCharArray(); int numVowels = 0; boolean lastWasVowel = false; for (char wc : currentWord) { boolean foundVowel = false; for (char v : vowels) { //don't count diphthongs if ((v == wc) && lastWasVowel) { foundVowel = true; lastWasVowel = true; break; } else if (v == wc && !lastWasVowel) { numVowels++; foundVowel = true; lastWasVowel = true; break; } } // If full cycle and no vowel found, set lastWasVowel to false; if (!foundVowel) lastWasVowel = false; } // Remove es, it's _usually? silent if (word.length() > 2 && word.substring(word.length() - 2) == "es") numVowels--; // remove silent e else if (word.length() > 1 && word.substring(word.length() - 1) == "e") numVowels--; return numVowels; } public static void main(String[] args) { String txt = "what"; System.out.println("txt="+txt+" countSyllables="+countSyllables(txt)); txt = "super"; System.out.println("txt="+txt+" countSyllables="+countSyllables(txt)); txt = "Maryland"; System.out.println("txt="+txt+" countSyllables="+countSyllables(txt)); txt = "American"; System.out.println("txt="+txt+" countSyllables="+countSyllables(txt)); txt = "disenfranchized"; System.out.println("txt="+txt+" countSyllables="+countSyllables(txt)); txt = "Sophia"; System.out.println("txt="+txt+" countSyllables="+countSyllables(txt)); } 

Результат был как и ожидалось (он работает достаточно хорошо для Flesch-Kincaid):

 txt=what countSyllables=1 txt=super countSyllables=2 txt=Maryland countSyllables=3 txt=American countSyllables=3 txt=disenfranchized countSyllables=5 txt=Sophia countSyllables=2 

Bumping @Tihamer и @ joe-basirico. Очень полезная функция, не идеальная , но хороша для большинства малых и средних проектов. Джо, я переписал реализацию вашего кода в Python:

 def countSyllables(word): vowels = "aeiouy" numVowels = 0 lastWasVowel = False for wc in word: foundVowel = False for v in vowels: if v == wc: if not lastWasVowel: numVowels+=1 #don't count diphthongs foundVowel = lastWasVowel = True break if not foundVowel: #If full cycle and no vowel found, set lastWasVowel to false lastWasVowel = False if len(word) > 2 and word[-2:] == "es": #Remove es - it's "usually" silent (?) numVowels-=1 elif len(word) > 1 and word[-1:] == "e": #remove silent e numVowels-=1 return numVowels 

Надеюсь, кто-то найдет это полезным!

Сегодня я нашел эту реализацию Java в алгоритме дефисности Фрэнка Ляна с шаблоном для английского или немецкого языка, который работает достаточно хорошо и доступен на Maven Central.

Пещера: важно удалить последние строки .tex шаблонов .tex , поскольку в противном случае эти файлы не могут быть загружены текущей версией на Maven Central.

Чтобы загрузить и использовать hyphenator , вы можете использовать следующий fragment кода Java. texTable – это имя .tex файлов, содержащих необходимые шаблоны. Эти файлы доступны на сайте github проекта.

  private Hyphenator createHyphenator(String texTable) { Hyphenator hyphenator = new Hyphenator(); hyphenator.setErrorHandler(new ErrorHandler() { public void debug(String guard, String s) { logger.debug("{},{}", guard, s); } public void info(String s) { logger.info(s); } public void warning(String s) { logger.warn("WARNING: " + s); } public void error(String s) { logger.error("ERROR: " + s); } public void exception(String s, Exception e) { logger.error("EXCEPTION: " + s, e); } public boolean isDebugged(String guard) { return false; } }); BufferedReader table = null; try { table = new BufferedReader(new InputStreamReader(Thread.currentThread().getContextClassLoader() .getResourceAsStream((texTable)), Charset.forName("UTF-8"))); hyphenator.loadTable(table); } catch (Utf8TexParser.TexParserException e) { logger.error("error loading hyphenation table: {}", e.getLocalizedMessage(), e); throw new RuntimeException("Failed to load hyphenation table", e); } finally { if (table != null) { try { table.close(); } catch (IOException e) { logger.error("Closing hyphenation table failed", e); } } } return hyphenator; } 

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

  String hyphenedTerm = hyphenator.hyphenate(term); String hyphens[] = hyphenedTerm.split("\u00AD"); int syllables = hyphens.length; 

Вам нужно разделить на "\u00AD », так как API не возвращает нормальный "-" .

Этот подход превосходит ответ Джо Базирико, поскольку он поддерживает множество разных языков и более точно определяет немецкую перенос.

Зачем рассчитывать? В каждом онлайн-словаре есть эта информация. http://dictionary.reference.com/browse/invisible in · vis · i · ble

Спасибо @ joe-basirico и @tihamer. Я портировал код @ tihamer на Lua 5.1, 5.2 и luajit 2 ( скорее всего, будет работать и на других версиях lua ):

countsyllables.lua

 function CountSyllables(word) local vowels = { 'a','e','i','o','u','y' } local numVowels = 0 local lastWasVowel = false for i = 1, #word do local wc = string.sub(word,i,i) local foundVowel = false; for _,v in pairs(vowels) do if (v == string.lower(wc) and lastWasVowel) then foundVowel = true lastWasVowel = true elseif (v == string.lower(wc) and not lastWasVowel) then numVowels = numVowels + 1 foundVowel = true lastWasVowel = true end end if not foundVowel then lastWasVowel = false end end if string.len(word) > 2 and string.sub(word,string.len(word) - 1) == "es" then numVowels = numVowels - 1 elseif string.len(word) > 1 and string.sub(word,string.len(word)) == "e" then numVowels = numVowels - 1 end return numVowels end 

И некоторые забавные тесты, чтобы подтвердить, что это работает ( насколько это необходимо ):

countsyllables.tests.lua

 require "countsyllables" tests = { { word = "what", syll = 1 }, { word = "super", syll = 2 }, { word = "Maryland", syll = 3}, { word = "American", syll = 4}, { word = "disenfranchized", syll = 5}, { word = "Sophia", syll = 2}, { word = "End", syll = 1}, { word = "I", syll = 1}, { word = "release", syll = 2}, { word = "same", syll = 1}, } for _,test in pairs(tests) do local resultSyll = CountSyllables(test.word) assert(resultSyll == test.syll, "Word: "..test.word.."\n".. "Expected: "..test.syll.."\n".. "Result: "..resultSyll) end print("Tests passed.") 

Я не мог найти адекватного способа подсчета слогов, поэтому сам разработал метод.

Вы можете просмотреть мой метод здесь: https://stackoverflow.com/a/32784041/2734752

Я использую комбинацию словаря и алгоритма для подсчета слогов.

Вы можете просмотреть мою библиотеку здесь: https://github.com/troywatson/Lawrence-Style-Checker

Я только что протестировал свой алгоритм и имел показатель забастовки 99,4%!

 Lawrence lawrence = new Lawrence(); System.out.println(lawrence.getSyllable("hyphenation")); System.out.println(lawrence.getSyllable("computer")); 

Вывод:

 4 3 

Некоторое время назад я столкнулся с этим вопросом.

Я закончил использование Словаря проспекта CMU для быстрого и точного поиска большинства слов. Для слов, не содержащихся в словаре, я вернулся к модели машинного обучения, которая на 98% точна при outlookировании количества слогов.

Я завернул все это в простой в использовании модуль python: https://github.com/repp/big-phoney

Установите: pip install big-phoney

Считайте слоги:

 from big_phoney import BigPhoney phoney = BigPhoney() phoney.count_syllables('triceratops') # --> 4 

Если вы не используете Python и хотите попробовать подход, основанный на модели ML, я подробно описал , как работает модель учета слогов в Kaggle .

Я использовал jsoup, чтобы сделать это один раз. Вот пример синтаксического анализатора:

 public String[] syllables(String text){ String url = "https://www.merriam-webster.com/dictionary/" + text; String relHref; try{ Document doc = Jsoup.connect(url).get(); Element link = doc.getElementsByClass("word-syllables").first(); if(link == null){return new String[]{text};} relHref = link.html(); }catch(IOException e){ relHref = text; } String[] syl = relHref.split("·"); return syl; } 
  • Java Stanford NLP: Часть лейблов речи?
  • Стермеры против Лемматизаторов
  • Как мне выполнить слово Stemming или Lemmatization?
  • Как разбить строку на слова. Пример: «stringintowords» -> «String Into Words»?
  • Неконтролируемый анализ настроений
  • Как обучить инструмент анализа настроений в НЛП Стэнфорда
  • Распознавание языков в Java
  • Как я могу разделить несколько соединенных слов?
  • Сеанс даты и времени для языка Java
  • Нечеткая строка поиска в Java
  • Разница между парсером и парсером зависимостей
  • Interesting Posts
    Давайте будем гением компьютера.