tonica silabas silaba separar para palabras online graves esdrujulas con clasificador buscar agudas nlp spell-checking hyphenation

nlp - silabas - Detectando sílabas en una palabra



palabras para separar en silabas (13)

Necesito encontrar una manera bastante eficiente de detectar sílabas en una palabra. P.ej,

Invisible -> in-vi-sib-le

Hay algunas reglas de silabificación que podrían usarse:

V CV VC CVC CCV CCCV CVCC

* donde V es una vocal y C es una consonante. P.ej,

Pronunciación (5 Pro-nun-ci-a-ción; CV-CVC-CV-V-CVC)

Probé algunos métodos, entre los que estaban usar regex (que solo ayuda si quieres contar sílabas) o definición de regla codificada (un enfoque de fuerza bruta que resulta ser muy ineficiente) y finalmente usar un autómata de estado finito (que sí lo hizo) no resulta con nada útil).

El propósito de mi aplicación es crear un diccionario de todas las sílabas en un idioma determinado. Este diccionario se usará más adelante para aplicaciones de corrección ortográfica (utilizando clasificadores Bayesianos) y síntesis de texto a voz.

Agradecería si uno pudiera darme consejos sobre una forma alternativa de resolver este problema además de mis enfoques anteriores.

Trabajo en Java, pero cualquier sugerencia en C / C ++, C #, Python, Perl ... podría funcionar para mí.



Aquí hay una solución usando 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()]]


Bumping @Tihamer y @ joe-basirico. Función muy útil, no perfecta , pero buena para la mayoría de los proyectos pequeños a medianos. Joe, he vuelto a escribir una implementación de tu código en 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

¡Espero que alguien encuentre esto útil!


Este es un problema particularmente difícil que no está completamente resuelto por el algoritmo de separación silábica LaTeX. Se puede encontrar un buen resumen de algunos métodos disponibles y los desafíos involucrados en el documento Evaluación de algoritmos de silabificación automática para inglés (Marchand, Adsett y Damper 2007).


Estoy tratando de abordar este problema para un programa que calculará el puntaje de lectura flesch-kincaid y flesch de un bloque de texto. Mi algoritmo usa lo que encontré en este sitio web: http://www.howmanysyllables.com/howtocountsyllables.html y se acerca razonablemente. Todavía tiene problemas con palabras complicadas como invisible y separación silábica, pero he descubierto que se mete en el estadio para mis propósitos.

Tiene la ventaja de ser fácil de implementar. Encontré que las "es" pueden ser silábicas o no. Es una apuesta, pero decidí eliminar las es en mi algoritmo.

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; }


Gracias @ joe-basirico y @tihamer. He transferido el código de @ tihamer a Lua 5.1, 5.2 y luajit 2 (lo más probable es que también se ejecute en otras versiones de 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

Y algunas pruebas divertidas para confirmar que funciona ( tanto como se supone ):

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.")


Gracias Joe Basirico, por compartir su implementación rápida y sucia en C #. He usado las grandes bibliotecas, y funcionan, pero generalmente son un poco lentas, y para proyectos rápidos, su método funciona bien.

Aquí está su código en Java, junto con casos de prueba:

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)); }

El resultado fue el esperado (funciona lo suficientemente bien para 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


Hoy encontré this implementación Java del algoritmo de división de palabras de Frank Liang con patrón para inglés o alemán, que funciona bastante bien y está disponible en Maven Central.

Cueva: es importante eliminar las últimas líneas de los archivos de patrones .tex , porque de lo contrario esos archivos no se pueden cargar con la versión actual en Maven Central.

Para cargar y usar el hyphenator , puede usar el siguiente fragmento de código Java. texTable es el nombre de los archivos .tex que contienen los patrones necesarios. Esos archivos están disponibles en el sitio del proyecto 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; }

Luego, el Hyphenator está listo para usar. Para detectar sílabas, la idea básica es dividir el término en los guiones proporcionados.

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

Debes dividir en "/u00AD ", ya que la API no devuelve un "-" normal.

Este enfoque supera la respuesta de Joe Basirico, ya que admite muchos idiomas diferentes y detecta la separación silábica alemana más precisa.


Lea sobre el enfoque de TeX para este problema a los efectos de la separación silábica. Especialmente vea la tesis de tesis de Frank Liang Word Hy-phen-a-tion de Com-put-er . Su algoritmo es muy preciso, y luego incluye un pequeño diccionario de excepciones para los casos donde el algoritmo no funciona.


Me encontré con esta página buscando lo mismo, y encontré algunas implementaciones del documento de Liang aquí: https://github.com/mnater/hyphenator

Eso es a menos que seas del tipo que disfruta leer una tesis de 60 páginas en lugar de adaptar el código disponible libremente para un problema no único. :)


No pude encontrar una manera adecuada de contar las sílabas, así que diseñé un método yo mismo.

Puede ver mi método aquí: https://.com/a/32784041/2734752

Utilizo una combinación de un diccionario y un método de algoritmo para contar las sílabas.

Puede ver mi biblioteca aquí: https://github.com/troywatson/Lawrence-Style-Checker

¡Acabo de probar mi algoritmo y tenía una tasa de ataque del 99.4%!

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

Salida:

4 3


Perl tiene Lingua::Phonology::Syllable Módulo Lingua::Phonology::Syllable . Puede probar eso o intente investigar su algoritmo. Vi algunos otros módulos más viejos allí, también.

No entiendo por qué una expresión regular te da solo un recuento de sílabas. Deberías poder obtener las sílabas usando paréntesis de captura. Asumiendo que puedes construir una expresión regular que funcione, eso es.


Usé jsoup para hacer esto una vez. Aquí hay un analizador sintáctico de sílaba:

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; }