Comment compter les syllabes dans un mot

22

Entrée: Vous recevrez une chaîne contenant un seul mot anglais. Toutes les lettres seront en minuscules et il n'y aura pas de caractères non alphabétiques dans la chaîne.

Sortie: Vous retournerez un entier de 1 à 7 représentant le nombre de syllabes que vous pensez être dans le mot.

Notation: votre programme sera exécuté par rapport à tous les mots trouvés dans ce référentiel . Si vous obtenez des Nmots corrects et que votre programme est Mvolumineux, alors votre score est N-(M*10). Le score le plus élevé l'emporte.

Pour générer mon nombre syllabe, je ce que ma liste de mots et ce à compter les syllabes.

Nathan Merrill
la source
Les mots de 3 syllabes contiennent "inn" et "ruby". Les mots de 2 syllabes contiennent ceux-ci: "irs", "ore", "roy", "yer". A part cela, les listes semblent assez précises.
juste la moitié du
@justhalf merci pour ces captures. La création des listes a certainement été la partie la plus difficile du défi.
Nathan Merrill
3
Ce défi me fait réaliser à quel point l’anglais peut être idiot. Prenons resumepar exemple ...
Sp3000

Réponses:

12

Ruby, 8618 correct (91,1%), 53 octets, 8618 - 10 * 53 = score 8088

->s{s.scan(/[aiouy]+e*|e(?!d$|ly).|[td]ed|le$/).size}

Il s'agit d'une fonction Ruby anonyme qui utilise des expressions rationnelles pour compter les syllabes.

La fonction ajoute une syllabe pour chaque instance de:

  • Une série de non- evoyelles, suivie de zéro de plus es
  • Un equi ne fait pas partie d'un suivi edou ely, à l'exception du suivi tedou deds
  • Une fuite le

Une analyse

L'idée de base est de compter les séries de voyelles, mais ce n'est pas très précis en soi (il [aeiouy]+est correct à 74%). La raison principale en est le silencee , qui modifie le son de voyelle précédent sans être prononcé lui-même. Par exemple, le mot slatea deux voyelles mais une seule syllabe.

Pour y faire face, nous retirons ela première partie de l'expression rationnelle et la traitons séparément. Détecter les es silencieux est difficile, mais j'ai trouvé deux cas où ils se produisent souvent:

  • Dans le cadre d'un suivi ed(sauf s'il s'agit d'un tedou dedcomme settledou saddled),
  • Dans le cadre d'une fuite evy(par exemple lovely)

Ces cas sont spécifiquement exclus de ce qui serait autrement e..

La raison de l' .entrée e(?!d$|ly).est de consommer le caractère suivant s'il y a une voyelle double (par exemple eaou ee), et de sorte qu'à ela fin du mot ne soit pas compté. Cependant, une fuite le est généralement prononcée, de sorte qu'elle est ajoutée à nouveau.

Enfin, les voyelles sont comptées comme une syllabe. Bien que cela ne soit pas toujours le cas (par exemple curious), il est souvent difficile de déterminer s'il existe plusieurs syllabes. Prenez le iade celestialet spatial, à titre d'exemple.

Programme de test

Je ne connais pas vraiment Ruby, donc je ne sais pas à quel point il peut être joué au golf. J'ai réussi à rassembler un programme de test en consultant beaucoup de SO cependant:

cases = 0
correct = 0

s = "->s{s.scan(/[aiouy]+e*|e(?!d$|ly).|[td]ed|le$/).size}"

f = eval s

for i in 1 ... 8
    filepath = i.to_s + "-syllable-words.txt"
    file = File.open(filepath)

    while (line = file.gets)
        word = line.strip
        cases += 1
        if f.call(word) == i
            correct += 1
        end
    end
end

p "Correct: #{correct}/#{cases}, Length: #{s.length}, Score: #{correct - s.length*10}"
Sp3000
la source
Aww, tu as fait le standard si haut. En Python, la longueur du code est exactement de 20 caractères de plus, donc mon implémentation de votre "voyelle suivie d'une lettre qui n'est pas e" donne 6638 (7158 correct)
juste
2
@justhalf C'est fondamentalement la seule raison pour laquelle j'utilise Ruby: PI utilise normalement Python pour tout le reste.
Sp3000
5

Python3, 7935 - 10 * 71 = 7225

Ma réponse rapide et sale: comptez les séries de voyelles consécutives, mais supprimez tout e final en premier.

lambda w:len(''.join(" x"[c in"aeiouy"]for c in w.rstrip('e')).split())

Après avoir supprimé les e, cela remplace les voyelles par xet tous les autres caractères par un espace. Le résultat est joint à nouveau dans une chaîne, puis divisé en espaces blancs. Idéalement, les espaces au début et à la fin sont ignorés (par exemple, " x xx ".split()donne ["x","xx"]). La longueur de la liste résultante est donc le nombre de groupes de voyelles.

La réponse originale de 83 octets ci-dessous était plus précise car elle ne supprimait qu'un seul e à la fin. Le plus récent a donc des problèmes pour des mots comme bee; mais le code raccourci l'emporte sur cet effet.

lambda w:len(''.join(" x"[c in"aeiouy"]for c in(w[:-1]if'e'==w[-1]else w)).split())

Programme de test:

syll = lambda w:len(''.join(c if c in"aeiouy"else' 'for c in w.rstrip('e')).split())

overallCorrect = overallTotal = 0
for i in range(1, 7):
    with open("%s-syllable-words.txt" % i) as f:
        words = f.read().split()
    correct = sum(syll(word) == i for word in words)
    total = len(words)
    print("%s: %s correct out of %s (%.2f%%)" % (i, correct, total, 100*correct/total))
    overallCorrect += correct
    overallTotal += total

print()
print("%s correct out of %s (%.2f%%)" % (overallCorrect, overallTotal, 100*overallCorrect/overallTotal))

Évidemment, c'était trop sale et pas assez rapide pour battre la réponse Ruby du Sp3000. ; ^)

DLosc
la source
->s{s.scan(/([aiouy]|e(?!$))+/).size}obtient 7583. 84% est assez impressionnant pour quelque chose de si simple.
Sp3000
1

Perl, 8145 - 3 * 30 = 7845

Utilisation des listes d'avant les commits récents.

#!perl -lp
$_=s/(?!e[ds]?$)[aeiouy]+//g
nutki
la source
Les fichiers ont été mis à jour récemment. J'ai jeté un coup d'œil et je n'ai pas vu les mots que vous avez nommés dans le fichier d'une syllabe.
Sp3000
@ Sp3000, weired. Ils ont été mis à jour il y a 7 heures selon ce que je vois, et il y a toujours ces mots sous ce lien: github.com/nathanmerrill/wordsbysyllables/blob/master/…
nutki
On dirait que @NathanMerrill a foiré la mise à jour il y a 7 heures: historique .
Sp3000
@ Sp3000, merci. Je mets à jour la partition vers l'ancienne version. Ces listes contiennent encore pas mal d'erreurs, mais pas aussi graves.
nutki
0

Python, 5370-10 * 19 = 5180

Ce programme suppose simplement que des mots plus longs signifient plus de syllabes.

lambda x:len(x)/6+1

Le programme de testeur que j'utilise est:

correct = 0
y = lambda x:len(x)/6+1
for i in xrange(1,8):
    f = file(str(i)+"-syllable-words.txt")
    lines = f.read().split("\n")
    f.close()
    correct += len([1 for line in lines if y(line)==i])
print correct
Nathan Merrill
la source
Faut-il créer un programme ou une fonction? Le vôtre n'est pas un programme, il ne produit rien lorsqu'il est exécuté.
juste la moitié du
@justhalf J'ai besoin de quelque chose qui accepte une entrée et produit une sortie (même si cette sortie n'est pas STDIO)
Nathan Merrill
Btw je n'ai pas obtenu 5150 pour utiliser 7, mais 4391. Dans mon test, il est préférable d'utiliser à la len(x)/6place (5377-190 = 5187).
juste la moitié du
@justhalf Avec les mises à jour, j'obtiens 5343, mais j'obtiens certainement un pire score avec len (x) / 6. Je publierai mon programme de test.
Nathan Merrill
readlines()inclut la nouvelle ligne dans le résultat. Donc le vôtre l'est en fait (len(x)+1)/7+1. Vous devez utiliser à la read().split('\n')place. Bien que j'aie eu 5352 pour cette formule, cependant.
juste