关于nlp:用一个词检测音节 您所在的位置:网站首页 world的音节数量 关于nlp:用一个词检测音节

关于nlp:用一个词检测音节

2024-06-13 05:39| 来源: 网络整理| 查看: 265

我需要找到一种相当有效的方法来检测单词中的音节。例如。,

看不见-> in-vi-sib-le

有一些音节化规则可以使用:

V 简历 风投 CVC CCV 中央电视台 CVCC

*其中V是元音,C是辅音。 例如。,

发音(5个专业名词; CV-CVC-CV-V-CVC)

我尝试了几种方法,其中包括使用正则表达式(仅在您要计算音节时才有用)或硬编码规则定义(被证明是效率很低的蛮力方法),最后使用了有限状态自动机(没有任何有用的结果)。

我的应用程序的目的是创建给定语言的所有音节的字典。该词典稍后将用于拼写检查应用程序(使用贝叶斯分类器)以及文本到语音的合成。

如果能在我以前的方法之外给我提示另一种解决此问题的方法,我将不胜感激。

我使用Java,但是使用C / C ++,C#,Python,Perl的任何技巧对我来说都可以。

相关讨论 您实际上是想要实际的分割点还是仅需要一个单词中的音节数? 如果是后者,请考虑在文本语音词典中查找单词,并计算编码元音的音素。 我猜想,最有效的方式(在计算方式上;在存储方式上不是)是将Python字典作为单词,将单词作为键,将音节的数量作为值。 但是,对于在字典中未使用的单词,您仍然需要进行备用。 让我知道您是否找到过这样的字典!

阅读有关TeX解决此问题的方法,以进行连接。特别是请参见计算机作者弗兰克·梁(Frank Liang)的论文论文"字样"。他的算法非常准确,然后针对该算法不起作用的情况提供了一个小的例外字典。

相关讨论 我喜欢您引用了有关该主题的论文,这对原始海报有一点暗示,那就是这可能不是一个简单的问题。 是的,我知道这不是一个简单的问题,尽管我还没有做很多工作。我确实低估了这个问题,我以为我可以在应用程序的其他部分上工作,后来又回到了这个简单的问题。愚蠢的我:) 我阅读了论文论文,发现它很有帮助。这种方法的问题在于,尽管我发现了一些可以生成这些模式的工具,但我没有阿尔巴尼亚语的任何模式。无论如何,出于我的目的,我写了一个基于规则的应用程序,解决了这个问题。 ...我的方法有点慢(在50K字文件上大约20秒),但我认为结果相当准确(我还没有任何有用的统计信息)。 我写了一篇简短的文章,对这种方法进行了一些测试,包括统计数据:allenporter.tumblr.com/post/9776954743/syllables-尽管断字法很有希望,但由于断字算法的存在,临时计算元音的方法似乎更准确连字符错误。据我所知,这绝对不是一个解决的问题。 @allenporter我阅读了您的网页。根据您的统计信息,连字方法不准确。我还阅读了2篇文章eprints.soton.ac.uk/264285/1/MarchandAdsettDamper_ISCA07.pdf和web.cs.dal.ca/~adsett/publications/AdsMar_CompSyllMeth_2009。 pdf格式您是否在他们的文章中了解SbA方法?他们声称连字正确率高达95%。您用于评估的那个大格(1 m大小)是多少?您能告诉我在哪里以及如何进行这种测试吗? 请注意,TeX算法用于查找合法的连字符点,这与音节分割并不完全相同。的确,连字符点属于音节分隔,但并非所有音节分隔都是有效的连字符点。例如,连字符arent(通常)用在单词两端的一个字母或两个字母之内。我还相信TeX模式已经过调整,可以在误报与误报之间进行权衡(即使在连字符都错掉的情况下,也不要放连字符)。 我也不相信连字符是答案。 但是,Liangs连字算法并不等同于分解成音节。例如。将其应用于"断字"会返回"断字",但分成音节,则应为"断字"(4个音节,而不是3个)。"项目"根本没有连字符,但分成音节,它将是"项目"(2个音节,而不是1个)。许多这样的情况

我偶然发现了这一页,寻找同样的东西,并在这里找到了Liang的一些实现: https://github.com/mnater/hyphenator或后继者:https://github.com/mnater/Hyphenopoly

除非您是喜欢阅读60页论文的类型,而不是针对非独特问题改编免费提供的代码。 :)

相关讨论 同意-使用现有的实现更方便

这是使用NLTK的解决方案:

1234from 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()]] 相关讨论 嘿,谢谢,我应该在函数def nsyl(word)中犯一个小错误:return [len(list(y表示x中的y,如果y [-1] .isdigit())表示d中的x [word.lower()] ] 对于该语料库中没有出现的单词,您有什么建议呢? @Pureferret cmudict是北美英语单词的发音词典。它将单词分解为音素,比音节短(例如cat这个单词被分解为三个音素:K-AE-T)。但是元音也有一个"重音标记":根据单词的发音为0、1或2(因此,猫中的AE变为AE1)。答案中的代码会计算重音标记,并因此计算出元音的数量-这有效地给出了音节的数量(请注意,在OP的示例中,每个音节恰好具有一个元音)。 这将返回音节的数量,而不是音节化。

我正在尝试为一个程序计算该问题,该程序将计算文本块的flesch-kincaid和flesch阅读分数。我的算法使用的是我在以下网站上找到的内容:http://www.howmanysyllables.com/howtocountsyllables.html,它的访问范围相当接近。它仍然难以处理诸如隐形和断字之类的复杂单词,但是我发现它出于我的目的而进入了球场。

它具有易于实现的优点。我发现" es"可以是音节,也可以不是。这是一场赌博,但我决定在算法中删除es。

123456789101112131415161718192021222324252627282930313233343536373839404142private 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)。

碰碰@Tihamer和@ joe-basirico。非常有用的功能,虽然不完美,但对大多数中小型项目都很有用。 Joe,我用Python重新编写了您的代码的实现:

123456789101112131415161718def 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

希望有人觉得这有用!

感谢Joe Basirico,感谢您共享C#中的快速而肮脏的实现。我使用了大型库,它们可以工作,但是它们通常有点慢,对于快速项目,您的方法可以正常工作。

这是您的Java代码以及测试用例:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354public 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来说效果足够好):

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

今天,我发现了Frank Liang的连字算法的Java实现,带有英语或德语的模式,该效果很好,可以在Maven Central上使用。

洞穴:删除.tex模式文件的最后几行很重要,因为否则这些文件将无法在Maven Central上以当前版本加载。

要加载和使用hyphenator,可以使用以下Java代码段。 texTable是包含所需模式的.tex文件的名称。这些文件可在项目github站点上找到。

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 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就可以使用了。要检测音节,基本思想是在提供的连字符处拆分术语。

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

您需要分割"\\u00AD",因为API不会返回普通的"-"。

这种方法优于Joe Basirico的答案,因为它支持许多不同的语言,并且可以更准确地检测德语连字。

为什么要计算呢?每个在线词典都有此信息。 http://dictionary.reference.com/browse/invisible 无形

相关讨论 也许它必须适用于字典中没有出现的单词,例如名称? @WouterLievens:我不认为名称足够接近用于自动音节解析的行为。英文名称的音节解析器在威尔士或苏格兰血统的名称上会惨遭失败,更不用说印度和尼日利亚血统的名称了,但是您可能会在例如伦敦。 必须牢记的是,考虑到这是对草图领域的纯粹启发式方法,期望获得比人类所能提供的更好的性能是不合理的。

Perl具有Lingua :: Phonology :: Syllable模块。您可以尝试一下,或尝试研究其算法。我也在那里看到了其他一些较旧的模块。

我不明白为什么正则表达式只给您一个音节数。您应该能够使用捕获括号来获取音节本身。假设您可以构造一个有效的正则表达式。

不久前,我遇到了这个完全相同的问题。

我最终使用了CMU发音词典来快速,准确地查找大多数单词。对于字典中没有的单词,我退回到了机器学习模型,该模型在预测音节数方面的准确度约为98%。

我将整个内容包装在一个易于使用的python模块中,网址为:https://github.com/repp/big-phoney

安装: pip install big-phoney

音节计数:

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

如果您不使用Python,并且想尝试基于ML模型的方法,那么我将对音节计数模型在Kaggle上的工作方式进行详尽的撰写。

相关讨论 这太酷了。有人能将生成的Keras模型转换为CoreML模型以在iOS上使用吗?

我找不到计算音节的适当方法,所以我自己设计了一个方法。

您可以在这里查看我的方法:https://stackoverflow.com/a/32784041/2734752

我结合使用字典和算法方法对音节进行计数。

您可以在这里查看我的图书馆:https://github.com/troywatson/Lawrence-Style-Checker

我刚刚测试了我的算法,点击率达到了99.4%!

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

输出:

124 3 相关讨论 通常,到工具或库的链接应随附使用说明,对链接资源如何适用于问题的具体说明,或一些示例代码,或者在可能的情况下,还应包括所有上述内容。 请参见语法突出显示。 SO编辑器中有一个帮助按钮(问号),可将您带到链接页面。

谢谢@ joe-basirico和@tihamer。我已经将@tihamer的代码移植到Lua 5.1、5.2和luajit 2(很可能也可以在其他版本的lua上运行):

countsyllables.lua

12345678910111213141516171819202122232425262728293031323334function 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

1234567891011121314151617181920212223242526require"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.."\ "..    "Expected:"..test.syll.."\ "..    "Result:"..resultSyll) end print("Tests passed.") 相关讨论 我添加了另外两个测试用例" End"和" I"。解决方法是不区分大小写地比较字符串。如果他们遇到相同的问题并希望更新其功能,请对@ joe-basirico和tihamer进行Ping操作。 @tihamer American是4个音节!

在进行了大量测试并尝试了断字连接程序包之后,我根据许多示例编写了自己的程序。我还尝试了与连字词典对接的pyhyphen和pyphen包,但在许多情况下它们产生的音节数错误。对于此用例,nltk包太慢了。

我在Python中的实现是我编写的类的一部分,并且音节计数例程粘贴在下面。由于我仍然没有找到解决无声单词结尾的好方法,因此它高估了音节的数量。

该函数返回用于Flesch-Kincaid可读性评分的每个单词的音节比率。该数字不一定是准确的,仅够估计即可。

在我的第7代i7 CPU上,此功能花了1.1-1.2毫秒来处理759个单词的示例文本。

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647def _countSyllablesEN(self, theText):     cleanText =""     for ch in theText:         if ch in"abcdefghijklmnopqrstuvwxyz'’":             cleanText += ch         else:             cleanText +=""     asVow    ="aeiouy'’"     dExep    = ("ei","ie","ua","ia","eo")     theWords = cleanText.lower().split()     allSylls = 0     for inWord in theWords:         nChar  = len(inWord)         nSyll  = 0         wasVow = False         wasY   = False         if nChar == 0:             continue         if inWord[0] in asVow:             nSyll += 1             wasVow = True             wasY   = inWord[0] =="y"         for c in range(1,nChar):             isVow  = False             if inWord[c] in asVow:                 nSyll += 1                 isVow = True             if isVow and wasVow:                 nSyll -= 1             if isVow and wasY:                 nSyll -= 1             if inWord[c:c+2] in dExep:                 nSyll += 1             wasVow = isVow             wasY   = inWord[c] =="y"         if inWord.endswith(("e")):             nSyll -= 1         if inWord.endswith(("le","ea","io")):             nSyll += 1         if nSyll < 1:             nSyll = 1         # print("%-15s: %d" % (inWord,nSyll))         allSylls += nSyll     return allSylls/len(theWords)

我用jsoup做了一次。这是一个示例音节解析器:

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

相关讨论 通用音节解析器如何?看起来这段代码只是在字典中查找音节



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有