Como contar as sílabas em uma palavra


22

Entrada: você receberá uma string contendo uma única palavra em inglês. Todas as letras serão minúsculas e não haverá caracteres não alfabéticos na sequência.

Saída: Você retornará um número inteiro de 1 a 7, representando quantas sílabas você acha que existem na palavra.

Pontuação: Seu programa será executado com todas as palavras encontradas neste repositório . Se você acertar as Npalavras e seu programa tiver Mbytes grandes, sua pontuação será N-(M*10). Maior pontuação ganha.

Para gerar minha contagem de sílabas, usei isso como minha lista de palavras e isso para contar as sílabas.


As 3 sílabas-palavras contêm "inn" e "ruby". As palavras de 2 sílabas contêm: "irs", "minério", "roy" e "yer". Fora isso, as listas parecem precisas o suficiente.
precisa saber é

@justhalf obrigado por essas capturas. Criar as listas foi definitivamente a parte mais difícil do desafio.
Nathan Merrill


3
Esse desafio está me fazendo perceber como o inglês pode ser tolo. Tomemos, resumepor exemplo ...
Sp3000 4/15

Respostas:


12

Ruby, 8618 correto (91,1%), 53 bytes, 8618 - 10 * 53 = pontuação do 8088

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

Esta é uma função Ruby anônima que usa expressões regulares para contar sílabas.

A função adiciona uma sílaba para cada instância de:

  • Uma sequência de não evogais, seguida por zero de mais es
  • Um eque não faz parte de um trailing edou ely, com exceção de trailing tedou deds
  • Um rastro le

Análise

A idéia básica é contar as execuções de vogais, mas isso por si só não é muito preciso ( [aeiouy]+fica 74% correto). A principal razão para isso é o silêncioe , que modifica o som da vogal anterior sem ser pronunciado. Por exemplo, a palavra slatetem duas vogais, mas apenas uma sílaba.

Para lidar com isso, retiramos ea primeira parte do regex e o tratamos separadamente. Detectar es silenciosos é difícil, mas encontrei dois casos em que ocorrem com frequência:

  • Como parte de uma fuga ed(a menos que seja uma tedou dedsemelhantes settledou saddled),
  • Como parte de uma trilha evy(por exemplo lovely)

Esses casos são especificamente excluídos do que seria de outra forma e..

A razão para a .em e(?!d$|ly).é consumir o próximo carvão animal se existe uma dupla vogal (por exemplo, eaou ee), e de modo que eno fim da palavra não são contados. No entanto, um final le é geralmente pronunciado, de modo que é adicionado novamente.

Finalmente, as execuções de vogais são contadas como uma sílaba. Embora nem sempre seja esse o caso (por exemplo curious), geralmente é difícil descobrir se há várias sílabas. Pegue o iade celestiale spatial, como um exemplo.

Programa de teste

Eu realmente não conheço Ruby, então não tenho certeza de quão bem ele pode ser jogado no golfe. Consegui reunir um programa de teste consultando muito SO:

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

Aww, você fez o padrão tão alto. No Python, o comprimento do código é exatamente 20 caracteres mais longo, então minha implementação da sua "Vogal seguida por uma letra que não é e" fornece 6638 (7158 correto)
justhalf 4/15/15

2
@justhalf É basicamente a única razão pela qual estou usando Ruby: o PI normalmente usa Python para todo o resto.
Sp3000 4/15

5

Python3, 7935 - 10 * 71 = 7225

Minha resposta rápida e suja: conte execuções de vogais consecutivas, mas remova qualquer e final primeiro.

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

Depois de retirar os e, isso substitui as vogais por x e todos os outros caracteres por um espaço. O resultado é unido novamente em uma sequência e depois dividido em espaço em branco. Convenientemente, os espaços em branco no início e no final são ignorados (por exemplo, " x xx ".split()["x","xx"]). O comprimento da lista resultante é, portanto, o número de grupos de vogais.

A resposta original de 83 bytes abaixo foi mais precisa, pois removeu apenas um e no final. O mais novo, portanto, tem problemas para palavras como bee; mas o código reduzido supera esse efeito.

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

Programa de teste:

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

Evidentemente, isso era muito sujo e não era rápido o suficiente para vencer a resposta Ruby do Sp3000. ; ^)


->s{s.scan(/([aiouy]|e(?!$))+/).size}pontuação 7583. 84% é bastante impressionante para algo tão simples.
Sp3000 4/15

1

Perl, 8145 - 3 * 30 = 7845

Usando as listas anteriores às confirmações recentes.

#!perl -lp
$_=s/(?!e[ds]?$)[aeiouy]+//g

Os arquivos foram atualizados recentemente. Dei uma olhada e não vi as palavras que você nomeou no arquivo de 1 sílaba.
Sp3000 4/03/15

@ Sp3000, distorcido. Eles onde atualizados 7 horas atrás de acordo com o que eu vejo, e ainda existem aquelas palavras sob esse link: github.com/nathanmerrill/wordsbysyllables/blob/master/...
nutki

Parece que @NathanMerrill estragou a atualização há 7 horas: history .
Sp3000 4/03/15

@ Sp3000, obrigado. Eu atualizo a pontuação para a versão mais antiga. Essas listas ainda têm alguns erros, mas não tão graves.
nutki

0

Python, 5370-10 * 19 = 5180

Este programa simplesmente assume que palavras mais longas significam mais sílabas.

lambda x:len(x)/6+1

O programa testador que eu uso é:

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

Devemos criar um programa ou uma função? O seu não é um programa, ele não produz nada quando é executado.
precisa saber é

@justhalf eu preciso de algo que aceita entrada e produz uma saída (mesmo que a saída não é STDIO)
Nathan Merrill

Aliás, não recebi 5150 por usar 7, mas 4391. No meu teste, é melhor usar len(x)/6(5377-190 = 5187).
Justhalf

@justhalf Com as atualizações, estou recebendo 5343, mas definitivamente obtendo uma pontuação pior com len (x) / 6. Vou postar meu programa de teste.
Nathan Merrill

readlines()inclui a nova linha no resultado. Então o seu é realmente (len(x)+1)/7+1. Você deve usar em seu read().split('\n')lugar. Embora eu tenha 5353 para essa fórmula, no entanto.
Just just
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.