检测单词中的音节
nlp
18
0

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

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

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

V CV VC CVC CCV CCCV CVCC

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

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

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

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

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

我使用Java,但是使用C / C ++,C#,Python,Perl的任何技巧都可以为我工作。

参考资料:
Stack Overflow
收藏
评论
共 10 个回答
高赞 时间 活跃

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

它具有易于实现的优点。我发现“ es”可以是音节,也可以不是。这是一场赌博,但我决定在算法中删除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;
    }
收藏
评论

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

收藏
评论

感谢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
收藏
评论

这是一个特别困难的问题,LaTeX断字算法无法完全解决。有关评估一些可用方法和所涉及挑战的详细信息,请参见《 评估英语自动音节化算法》 (Marchand,Adsett和Damper 2007)。

收藏
评论

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

收藏
评论

我偶然发现了该页面以寻找相同的内容,并在此处找到了Liang论文的一些实现: https : //github.com/mnater/hyphenator

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

收藏
评论

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

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

收藏
评论

今天,我发现这个 Java实现弗兰克·梁与英语或德语,它工作得很好,并提供对Maven的中央图案断字algorithmn的。

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

要加载和使用hyphenator ,可以使用以下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不会返回普通的"-"

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

收藏
评论

碰碰@Tihamer和@ joe-basirico。非常有用的功能,不是很完美 ,但是对大多数中小型项目都很有用。 Joe,我用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

希望有人觉得这有用!

收藏
评论

这是使用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()]] 
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号