150

単語の音節を検出するかなり効率的な方法を見つける必要があります。例えば、

目に見えない -> in-vi-sib-le

使用できる音節規則がいくつかあります。

V CV VC CVC CCV CCCV CVCC

※Vは母音、Cは子音です。例えば、

発音 (5 Pro-nun-ci-ation; CV-CVC-CV-V-CVC)

私はいくつかの方法を試しましたが、その中には正規表現 (音節を数えたい場合にのみ役立ちます) またはハードコードされたルール定義 (非常に非効率的であることが証明された力ずくのアプローチ) を使用し、最後に有限状態オートマトン (これは有用なものにはなりません)。

私のアプリケーションの目的は、特定の言語のすべての音節の辞書を作成することです。このディクショナリは、後でスペル チェック アプリケーション (ベイジアン分類子を使用) およびテキストから音声への合成に使用されます。

以前のアプローチ以外に、この問題を解決する別の方法についてのヒントを教えていただければ幸いです。

私は Java で仕事をしていますが、C/C++、C#、Python、Perl のヒントなら何でも役に立ちます。

4

17 に答える 17

132

ハイフネーションの目的で、この問題に対する TeX のアプローチについて読んでください。特に、Frank Liang の学位論文 Word Hy-phen-a-tion by Comp-put-erを参照してください。彼のアルゴリズムは非常に正確で、アルゴリズムが機能しない場合のための小さな例外辞書が含まれています。

于 2009-01-01T17:17:58.890 に答える
48

私は同じことを探してこのページに出くわし、ここでLiangペーパーのいくつかの実装を見つけました: https ://github.com/mnater/hyphenatorまたは後継者:https ://github.com/mnater/Hyphenopoly

それは、あなたが60ページの論文を読むことを楽しむタイプでない限り、非固有の問題に自由に利用できるコードを適応させるのではありません。:)

于 2009-01-02T07:19:44.887 に答える
43

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()]] 
于 2010-11-05T02:52:20.400 に答える
20

私は、テキスト ブロックのフレッシュ キンケイドとフレッシュ リーディング スコアを計算するプログラムで、この問題に取り組もうとしています。私のアルゴリズムは、この Web サイト ( http://www.howmanysyllables.com/howtocountsyllables.html ) で見つけたものを使用しており、かなり近いものになっています。invisible やハイフネーションなどの複雑な単語にはまだ問題がありますが、私の目的には大体合っていることがわかりました。

導入しやすいというメリットがあります。「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;
    }
于 2011-04-11T00:34:28.123 に答える
8

これは特に難しい問題であり、LaTeX のハイフネーション アルゴリズムでは完全には解決されません。いくつかの利用可能な方法と関連する課題の優れた要約は、Evaluating Automatic Syllabification Algorithms for English (Marchand、Adsett、および Damper 2007) という論文に記載されています。

于 2011-02-07T15:40:54.953 に答える
6

@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

誰かがこれが役に立つことを願っています!

于 2015-10-14T06:18:04.690 に答える
6

なぜそれを計算するのですか?すべてのオンライン辞書にこの情報があります。http://dictionary.reference.com/browse/invisible in·vis·i·ble

于 2010-02-20T02:44:51.567 に答える
4

Perl にはLingua::Phonology::Syllableモジュールがあります。それを試すか、そのアルゴリズムを調べてみてください。そこには他にもいくつかの古いモジュールがありました。

正規表現で音節の数だけが得られる理由がわかりません。キャプチャ括弧を使用して音節自体を取得できるはずです。つまり、機能する正規表現を構築できると仮定します。

于 2009-01-01T17:34:03.260 に答える
4

今日、英語またはドイツ語のパターンを使用した Frank Liang のハイフネーション アルゴリズムの Java 実装を見つけまし。これは非常にうまく機能し、Maven Central で利用できます。

洞窟:.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;

API"\u00ADは通常の"-".

このアプローチは、多くの異なる言語をサポートし、ドイツ語のハイフネーションをより正確に検出するため、Joe Basirico の回答よりも優れています。

于 2016-02-17T14:40:28.803 に答える
1

音節を数える適切な方法が見つからなかったので、自分で方法を設計しました。

ここで私の方法を見ることができます: 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
于 2015-09-25T15:44:12.213 に答える
0

Rで「問題なく」機能するソリューションを含めています。完璧にはほど遠いです。

countSyllablesInWord = function(words)
  {
  #word = "super";
  n.words = length(words);
  result = list();
  for(j in 1:n.words)
    {
    word = words[j];
    vowels = c("a","e","i","o","u","y");
    
    word.vec = strsplit(word,"")[[1]];
    word.vec;
    
    n.char = length(word.vec);
    
    is.vowel = is.element(tolower(word.vec), vowels);
    n.vowels = sum(is.vowel);
    
    
    # nontrivial problem 
    if(n.vowels <= 1)
      {
      syllables = 1;
      str = word;
      } else {
              # syllables = 0;
              previous = "C";
              # on average ? 
              str = "";
              n.hyphen = 0;
        
              for(i in 1:n.char)
                {
                my.char = word.vec[i];
                my.vowel = is.vowel[i];
                if(my.vowel)
                  {
                  if(previous == "C")
                    {
                    if(i == 1)
                      {
                      str = paste0(my.char, "-");
                      n.hyphen = 1 + n.hyphen;
                      } else {
                              if(i < n.char)
                                {
                                if(n.vowels > (n.hyphen + 1))
                                  {
                                  str = paste0(str, my.char, "-");
                                  n.hyphen = 1 + n.hyphen;
                                  } else {
                                           str = paste0(str, my.char);
                                          }
                                } else {
                                        str = paste0(str, my.char);
                                        }
                              }
                     # syllables = 1 + syllables;
                     previous = "V";
                    } else {  # "VV"
                          # assume what  ?  vowel team?
                          str = paste0(str, my.char);
                          }
            
                } else {
                            str = paste0(str, my.char);
                            previous = "C";
                            }
                #
                }
        
              syllables = 1 + n.hyphen;
              }
  
      result[[j]] = list("syllables" = syllables, "vowels" = n.vowels, "word" = str);
      }
  
  if(n.words == 1) { result[[1]]; } else { result; }
  }

以下にいくつかの結果を示します。

my.count = countSyllablesInWord(c("America", "beautiful", "spacious", "skies", "amber", "waves", "grain", "purple", "mountains", "majesty"));

my.count.df = data.frame(matrix(unlist(my.count), ncol=3, byrow=TRUE));
colnames(my.count.df) = names(my.count[[1]]);

my.count.df;

#    syllables vowels         word
# 1          4      4   A-me-ri-ca
# 2          4      5 be-auti-fu-l
# 3          3      4   spa-ci-ous
# 4          2      2       ski-es
# 5          2      2       a-mber
# 6          2      2       wa-ves
# 7          2      2       gra-in
# 8          2      2      pu-rple
# 9          3      4  mo-unta-ins
# 10         3      3    ma-je-sty

これが「うさぎの穴」の大きさだとは思いもしませんでした。


################ hackathon #######


# https://en.wikipedia.org/wiki/Gunning_fog_index
# THIS is a CLASSIFIER PROBLEM ...
# https://stackoverflow.com/questions/405161/detecting-syllables-in-a-word



# http://www.speech.cs.cmu.edu/cgi-bin/cmudict
# http://www.syllablecount.com/syllables/


  # https://enchantedlearning.com/consonantblends/index.shtml
  # start.digraphs = c("bl", "br", "ch", "cl", "cr", "dr", 
  #                   "fl", "fr", "gl", "gr", "pl", "pr",
  #                   "sc", "sh", "sk", "sl", "sm", "sn",
  #                   "sp", "st", "sw", "th", "tr", "tw",
  #                   "wh", "wr");
  # start.trigraphs = c("sch", "scr", "shr", "sph", "spl",
  #                     "spr", "squ", "str", "thr");
  # 
  # 
  # 
  # end.digraphs = c("ch","sh","th","ng","dge","tch");
  # 
  # ile
  # 
  # farmer
  # ar er
  # 
  # vowel teams ... beaver1
  # 
  # 
  # # "able"
  # # http://www.abcfastphonics.com/letter-blends/blend-cial.html
  # blends = c("augh", "ough", "tien", "ture", "tion", "cial", "cian", 
  #             "ck", "ct", "dge", "dis", "ed", "ex", "ful", 
  #             "gh", "ng", "ous", "kn", "ment", "mis", );
  # 
  # glue = c("ld", "st", "nd", "ld", "ng", "nk", 
  #           "lk", "lm", "lp", "lt", "ly", "mp", "nce", "nch", 
  #           "nse", "nt", "ph", "psy", "pt", "re", )
  # 
  # 
  # start.graphs = c("bl, br, ch, ck, cl, cr, dr, fl, fr, gh, gl, gr, ng, ph, pl, pr, qu, sc, sh, sk, sl, sm, sn, sp, st, sw, th, tr, tw, wh, wr");
  # 
  # # https://mantra4changeblog.wordpress.com/2017/05/01/consonant-digraphs/
  # digraphs.start = c("ch","sh","th","wh","ph","qu");
  # digraphs.end = c("ch","sh","th","ng","dge","tch");
  # # https://www.education.com/worksheet/article/beginning-consonant-blends/
  # blends.start = c("pl", "gr", "gl", "pr",
  #                 
  # blends.end = c("lk","nk","nt",
  # 
  # 
  # # https://sarahsnippets.com/wp-content/uploads/2019/07/ScreenShot2019-07-08at8.24.51PM-817x1024.png
  # # Monte     Mon-te
  # # Sophia    So-phi-a
  # # American  A-mer-i-can
  # 
  # n.vowels = 0;
  # for(i in 1:n.char)
  #   {
  #   my.char = word.vec[i];
  # 
  # 
  # 
  # 
  # 
  # n.syll = 0;
  # str = "";
  # 
  # previous = "C"; # consonant vs "V" vowel
  # 
  # for(i in 1:n.char)
  #   {
  #   my.char = word.vec[i];
  #   
  #   my.vowel = is.element(tolower(my.char), vowels);
  #   if(my.vowel)
  #     {
  #     n.vowels = 1 + n.vowels;
  #     if(previous == "C")
  #       {
  #       if(i == 1)
  #         {
  #         str = paste0(my.char, "-");
  #         } else {
  #                 if(n.syll > 1)
  #                   {
  #                   str = paste0(str, "-", my.char);
  #                   } else {
  #                          str = paste0(str, my.char);
  #                         }
  #                 }
  #        n.syll = 1 + n.syll;
  #        previous = "V";
  #       } 
  #     
  #   } else {
  #               str = paste0(str, my.char);
  #               previous = "C";
  #               }
  #   #
  #   }
  # 
  # 
  # 
  # 
## https://jzimba.blogspot.com/2017/07/an-algorithm-for-counting-syllables.html
# AIDE   1
# IDEA   3
# IDEAS  2
# IDEE   2
# IDE   1
# AIDA   2
# PROUSTIAN 3
# CHRISTIAN 3
# CLICHE  1
# HALIDE  2
# TELEPHONE 3
# TELEPHONY 4
# DUE   1
# IDEAL  2
# DEE   1
# UREA  3
# VACUO  3
# SEANCE  1
# SAILED  1
# RIBBED  1
# MOPED  1
# BLESSED  1
# AGED  1
# TOTED  2
# WARRED  1
# UNDERFED 2
# JADED  2
# INBRED  2
# BRED  1
# RED   1
# STATES  1
# TASTES  1
# TESTES  1
# UTILIZES  4

そして、良い尺度として、単純なkincaid読みやすさ関数... sylablesは、最初の関数から返されたカウントのリストです...

私の関数はより多くの音節に少し偏っているので、読みやすさのスコアが高くなります...今のところは問題ありません...目標がテキストを読みやすくすることである場合、これは最悪のことではありません.

computeReadability = function(n.sentences, n.words, syllables=NULL)
  {
  n = length(syllables);
  n.syllables = 0;
  for(i in 1:n)
    {
    my.syllable = syllables[[i]];
    n.syllables = my.syllable$syllables + n.syllables;
    }
  # Flesch Reading Ease (FRE):
  FRE = 206.835 - 1.015 * (n.words/n.sentences) - 84.6 * (n.syllables/n.words);
  # Flesh-Kincaid Grade Level (FKGL):
  FKGL = 0.39 * (n.words/n.sentences) + 11.8 * (n.syllables/n.words) - 15.59; 
  # FKGL = -0.384236 * FRE - 20.7164 * (n.syllables/n.words) + 63.88355;
  # FKGL = -0.13948  * FRE + 0.24843 * (n.words/n.sentences) + 13.25934;
  
  list("FRE" = FRE, "FKGL" = FKGL); 
  }
于 2020-11-19T01:48:40.687 に答える