Cómo contar las sílabas en una palabra

22

Entrada: se le pasará una cadena que contiene una sola palabra en inglés. Todas las letras estarán en minúsculas y no habrá caracteres no alfabéticos en la cadena.

Salida: devolverá un número entero del 1 al 7 que representa cuántas sílabas cree que hay en la palabra.

Puntuación: su programa se ejecutará contra todas las palabras que se encuentran en este repositorio . Si obtienes Npalabras correctas y tu programa es de Mbytes grandes, entonces tu puntaje es N-(M*10). Mayor puntuación gana.

Para generar mi conteo de sílabas, utilicé esto como mi lista de palabras y esto para contar las sílabas.

Nathan Merrill
fuente
Las palabras de 3 sílabas contienen "posada" y "rubí". Las palabras de 2 sílabas contienen estas: "irs", "ore", "roy", "yer". Aparte de eso, las listas parecen lo suficientemente precisas.
justhalf
@ justhalf gracias por esas capturas. Crear las listas fue definitivamente la parte más difícil del desafío.
Nathan Merrill
3
Este desafío me hace darme cuenta de lo tonto que puede ser el inglés. Tomemos resumepor ejemplo ...
Sp3000

Respuestas:

12

Ruby, 8618 correcto (91.1%), 53 bytes, 8618-10 * 53 = 8088 puntaje

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

Esta es una función de Ruby anónima que utiliza expresiones regulares para contar sílabas.

La función agrega una sílaba para cada instancia de:

  • Una serie de no evocales, seguida de cero de más es
  • Un eque no es parte de un final edo ely, con la excepción de final tedo deds
  • Un final le

Análisis

La idea básica es contar series de vocales, pero esto por sí solo no es muy preciso ( [aeiouy]+obtiene un 74% correcto). La razón principal de esto es debido al silencioe , que modifica el sonido vocal anterior sin ser pronunciado. Por ejemplo, la palabra slatetiene dos vocales pero solo una sílaba.

Para lidiar con esto, sacamos ela primera parte de la expresión regular y la tratamos por separado. Detectar es silencioso es difícil, pero encontré dos casos en los que ocurren con frecuencia:

  • Como parte de un seguimiento ed(a menos que sea un tedo dedcomo settledo saddled),
  • Como parte de un seguimiento evy(por ejemplo lovely)

Estos casos están específicamente excluidos de lo que de otro modo sería e..

La razón de la .en e(?!d$|ly).es consumir la siguiente Char si hay un doble vocal (por ejemplo, eao ee), y de modo que eal final de la palabra no se cuentan. Sin embargo, un trailing le se pronuncia generalmente, de modo que se añade de nuevo.

Finalmente, las corridas vocales se cuentan como una sílaba. Si bien esto puede no ser siempre el caso (p curious. Ej. ), A menudo es difícil determinar si hay varias sílabas. Tome el iade celestialy spatial, como ejemplo.

Programa de prueba

Realmente no conozco a Ruby, así que no estoy seguro de qué tan bien se puede jugar al golf. Sin embargo, logré reunir un programa de prueba consultando mucho 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}"
Sp3000
fuente
Aww, hiciste el estándar tan alto. En Python, la longitud del código es exactamente 20 caracteres más larga, por lo que mi implementación de su "Vocal seguida de una letra que no es e" da 6638 (7158 correcto)
solo el
2
@justhalf Es básicamente la única razón por la que estoy usando Ruby: PI normalmente usa Python para todo lo demás.
Sp3000
5

Python3, 7935-10 * 71 = 7225

Mi respuesta rápida y sucia: cuenta las corridas de vocales consecutivas, pero elimina primero cualquier e final.

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

Después de quitar las e, esto reemplaza las vocales con xy todos los demás caracteres con un espacio. El resultado se vuelve a unir en una cadena y luego se divide en espacios en blanco. Convenientemente, el espacio en blanco al principio y al final se ignora (por ejemplo, " x xx ".split()da ["x","xx"]). La longitud de la lista resultante es, por lo tanto, el número de grupos de vocales.

La respuesta original de 83 bytes a continuación fue más precisa porque solo eliminó una sola e al final. El más nuevo tiene problemas para palabras como bee; pero el código acortado supera ese efecto.

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

Programa de prueba:

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, esto era demasiado sucio y no lo suficientemente rápido como para superar la respuesta de Ruby de Sp3000. ; ^)

DLosc
fuente
->s{s.scan(/([aiouy]|e(?!$))+/).size}puntajes 7583. 84% es bastante impresionante para algo tan simple.
Sp3000
1

Perl, 8145 - 3 * 30 = 7845

Usando las listas anteriores a los commits recientes.

#!perl -lp
$_=s/(?!e[ds]?$)[aeiouy]+//g
nutki
fuente
Los archivos han sido actualizados recientemente. Eché un vistazo y no vi las palabras que nombró en el archivo de 1 sílaba.
Sp3000
@ Sp3000, cansado. Se actualizaron hace 7 horas según lo que veo, y todavía hay esas palabras en ese enlace: github.com/nathanmerrill/wordsbysyllables/blob/master/…
nutki
Parece que @NathanMerrill estropeó la actualización hace 7 horas: historial .
Sp3000
@ Sp3000, gracias. Actualizo el puntaje a la versión anterior. Esas listas aún tienen bastantes errores, pero no tan graves.
nutki
0

Python, 5370-10 * 19 = 5180

Este programa simplemente supone que las palabras más largas significan más sílabas.

lambda x:len(x)/6+1

El programa de prueba que uso es:

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
fuente
¿Deberíamos crear un programa o una función? El suyo no es un programa, no genera nada cuando se ejecuta.
justhalf
@justhalf Necesito algo que acepte entradas y produzca salidas (incluso si esa salida no es STDIO)
Nathan Merrill
Por cierto, no obtuve 5150 por usar 7, pero 4391. En mi prueba, es mejor usarlo len(x)/6(5377-190 = 5187).
justhalf
@justhalf Con las actualizaciones, obtengo 5343, pero definitivamente obtengo un puntaje peor con len (x) / 6. Publicaré mi programa de prueba.
Nathan Merrill
readlines()incluye la nueva línea en el resultado. Entonces el tuyo es en realidad (len(x)+1)/7+1. Deberías usar read().split('\n')en su lugar. Aunque obtuve 5352 para esa fórmula, sin embargo.
justhalf