Frage

Ich brauche eine ziemlich effiziente Art und Weise finden Silben in einem Wort zu erkennen. Z.B.

Unsichtbar -> in-vi-sib-le

Es gibt einige syllabification Regeln, die verwendet werden könnten:

V Lebenslauf VC CVC CCV CC CV CVCC

*, wobei V ein Vokal und C ist ein Konsonant. Zum Beispiel,

Aussprache (5 Pro-Nonne-ci-a-tion; CV-CVC-CV-V-CVC)

Ich habe einige Methoden versucht, unter denen regex wurden mit oder hartcodierte Regeldefinition (ein Brute-Force-Ansatz, der sehr ineffizient erweist) (das nur, wenn Sie wollen Silben zählen hilft) und schließlich einen endlichen Automaten mit (das führte nicht mit irgendetwas nützlich).

Der Zweck meiner Anwendung ist ein Wörterbuch aller Silben in einer bestimmten Sprache zu erstellen. Das Wörterbuch wird später für die Rechtschreibprüfung von Anwendungen (unter Verwendung von Bayes-Klassifizierer) verwendet werden, und Text-zu-Sprache-Synthese.

Ich würde schätzen, wenn man mir Tipps auf einem anderen Weg geben könnte dieses Problem neben meinen bisherigen Ansätzen zu lösen.

Ich arbeite in Java, aber jede Spitze in C / C ++, C #, Python, Perl ... für mich funktionieren würde.

War es hilfreich?

Lösung

Lesen Sie über die TeX Ansatz für dieses Problem für die Zwecke der hyphenation. sehen vor allem Frank Liang Dissertation Dissertation Word-Hy-Phen-a-tion von Com- put-er . Sein Algorithmus ist sehr genau und schließt dann eine kleine Ausnahmen Wörterbuch für Fälle, in denen der Algorithmus nicht funktioniert.

Andere Tipps

ich auf diese Seite gestolpert für die gleiche Sache suchen, und einige Implementierungen des Liang Papier finden Sie hier: https://github.com/mnater/hyphenator

Das ist, wenn Sie der Typ, die eine 60-seitigen Dissertation statt Anpassung frei verfügbaren Code für nicht eindeutiges Problem gerne lesen. :)

Hier ist eine Lösung mit 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()]] 

Ich versuche, dieses Problem für ein Programm zu beseitigen, die die Flesch-Kincaid und flesch Lesen Partitur eines Textblock wird berechnet werden. Mein Algorithmus verwendet, was ich auf dieser Website: http://www.howmanysyllables.com/howtocountsyllables.html und es wird ziemlich nahe. Es hat immer noch Probleme auf komplizierte Wörter wie unsichtbar und Silbentrennung, aber ich habe festgestellt, es für meine Zwecke im Baseballstadion bekommt.

Es hat den Kopf, dass sie einfach zu implementieren. Ich fand das „es“ kann entweder syllabic sein oder nicht. Es ist ein Glücksspiel, aber ich beschlossen, die es in meinem Algorithmus zu entfernen.

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

Dies ist ein besonders schwieriges Problem, das nicht vollständig durch die LaTeX Trennungs-Algorithmen gelöst. Eine gute Zusammenfassung einiger verfügbaren Methoden und die Herausforderungen, die sich im Papier Auswertung Automatische Silbentrennung Algorithmen für Englisch (Marchand, Adsett und Dämpfer 2007).

Danke Joe Basirico, für Ihre schnelle und schmutzige Implementierung in C # zu teilen. Ich habe die großen Bibliotheken verwendet, und sie arbeiten, aber sie sind in der Regel ein bisschen langsam, und für schnelle Projekte, Ihre Methode funktioniert gut.

Hier ist der Code in Java, zusammen mit Testfällen:

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

Das Ergebnis wurde wie erwartet (es funktioniert gut genug für 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 und @ joe-basirico. Sehr nützliche Funktion, nicht perfekt , aber gut für die meisten kleinen bis mittleren Projekten. Joe, ich habe eine Implementierung des Codes in Python neu geschrieben:

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

Hope jemand findet diese nützlich!

Perl hat Lingua :: Phonology :: Syllable Modul. Sie könnten versuchen, das, oder versuchen, in seinen Algorithmus suchen. Ich sah ein paar andere älteren Module auch da.

Ich verstehe nicht, warum ein regulärer Ausdruck nur eine Anzahl von Silben gibt. Sie sollten die Silben selbst capture Klammern mit bekommen können. Angenommen, Sie können einen regulären Ausdruck konstruieren, das funktioniert, das ist.

Heute habe ich diese Java-Implementierung von Frank Liang hyphenation Algorithmus mit Muster für Englisch oder Deutsch , die funktioniert ganz gut und auf Maven Zentrale zur Verfügung.

Cave:. Es ist wichtig, die letzten Zeilen der .tex Pattern-Dateien zu entfernen, da sonst die Dateien nicht mit der aktuellen Version auf Maven Zentrale geladen werden

Um die hyphenator zu laden und verwenden, können Sie den folgenden Java-Code-Snippet verwenden. texTable ist der Name der .tex Dateien die benötigten Muster enthält. Diese Dateien sind auf der Projekt Github-Website zur Verfügung.

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

Danach wird die Hyphenator ist einsatzbereit. Zur Erkennung von Silben, ist die Grundidee, den Begriff an den vorgesehenen Bindestrichen zu trennen.

    String hyphenedTerm = hyphenator.hyphenate(term);

    String hyphens[] = hyphenedTerm.split("\u00AD");

    int syllables = hyphens.length;

Sie müssen sich auf "\u00AD“spalten, da die API keine normale "-" zurückgibt.

Dieser Ansatz übertrifft die Antwort von Joe Basirico, da es viele verschiedenen Sprachen und erkennt deutsche hyphenation genauer.

unterstützt

Warum es berechnen? Jeder Online-Wörterbuch hat diese Info. http://dictionary.reference.com/browse/invisible in · vis · i · ble

Danke @ joe-basirico und @tihamer. Ich habe @ Tihamer den Code zu Lua portiert 5.1, 5.2 und luajit 2 ( höchstwahrscheinlich auf anderen Versionen von lua laufen auch ):

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

Und einige Spaß Tests zu bestätigen es funktioniert ( so viel wie es angenommen hat, zu ):

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

Ich konnte keine angemessene Art und Weise zu zählen Silben finden, so habe ich eine Methode selbst.

https://stackoverflow.com/a/32784041/2734752 Sie können meine Methode hier ansehen >

Ich verwende eine Kombination aus einem Wörterbuch und Algorithmus Methode Silben zu zählen.

Sie können meine Bibliothek hier lesen: https://github.com/troywatson/Lawrence- Style-Checker

ich gerade getestet meinen Algorithmus und hatte eine 99,4% Trefferquote!

Lawrence lawrence = new Lawrence();

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

Ausgabe:

4
3

Ich lief in dieser genau die gleiche Frage vor einiger Zeit.

Ich landete mit dem CMU Aussprache-Wörterbuch für die schnellen und genaue Lookups der meisten Wörter. Für Worte nicht im Wörterbuch, fiel ich zurück zu einem maschinellen Lernmodell, das bei der Vorhersage Silbe zählt ~ 98% korrekt ist.

Ich wickelte die ganze Sache in einer einfach zu bedienende Python-Modul hier: https: // github.com/repp/big-phoney

Installieren: pip install big-phoney

Syllables Count:

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

Wenn Sie nicht mit Python und Sie den ML-Modell-basierten Ansatz, um zu versuchen, ich habe ein ziemlich detaillierten schreiben auf, wie die Silbe Zählung Modell funktioniert auf Kaggle .

Nachdem eine Menge Tests zu tun und auch hyphenation Pakete auszuprobieren, schrieb ich meine eigenen basierend auf einer Reihe von Beispielen. Ich habe auch versucht die pyhyphen und pyphen Pakete, die mit hyphenation Wörterbücher Schnittstellen, aber sie produzieren die falsche Anzahl von Silben in vielen Fällen. Das nltk Paket war einfach zu langsam für diesen Anwendungsfall.

Meine Implementierung in Python ist Teil einer Klasse i geschrieben, und die Silbe Routine zu zählen ist unten eingefügt. Es überschätzt die Anzahl der Silben ein bisschen wie ich habe noch nicht eine gute Art und Weise zu machen stille Wortendungen.

gefunden

Die Funktion gibt das Verhältnis von Silben pro Wort, wie es für eine Flesch-Kincaid Lesbarkeit Score verwendet wird. Die Zahl muss nicht genau sein, gerade genug, um in der Nähe für eine Schätzung.

Auf meinem 7. Generation i7 CPU, nahm diese Funktion 1,1-1,2 Millisekunden für eine 759 Wort Beispieltext.

def _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)

habe ich jsoup einmal zu machen. Hier ist ein Beispiel Silbenanalysierer:

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;
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top