Как считать слоги в слове

22

Входные данные: вам будет передана строка, содержащая одно английское слово. Все буквы будут строчными, и в строке не будет не алфавитных символов.

Вывод: вы вернете целое число от 1 до 7, представляющее, сколько слогов вы думаете в слове.

Оценка: Ваша программа будет работать со всеми словами, найденными в этом хранилище . Если вы получаете Nправильные слова, и ваша программа имеет Mбольшие байты, значит, ваш результат равен N-(M*10). Наибольший счет выигрывает.

Чтобы сгенерировать количество слогов, я использовал это в качестве списка слов и это для подсчета слогов.

Натан Меррилл
источник
3-слоговые слова содержат слова «гостиница» и «рубин». 2-слоговые слова содержат эти слова: «ир», «руда», «рой», «йер». Кроме этого списки кажутся достаточно точными.
полугодие
@justhalf спасибо за эти уловы. Создание списков было определенно самой сложной частью задачи.
Натан Меррилл,
Связанный: codegolf.stackexchange.com/questions/10533/…
Цифровая травма
3
Эта проблема заставляет меня понять, насколько глупым может быть английский. Взять resumeк примеру ...
Sp3000

Ответы:

12

Ruby, 8618 правильных (91,1%), 53 байта, 8618 - 10 * 53 = 8088 баллов

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

Это анонимная функция Ruby, которая использует регулярные выражения для подсчета слогов.

Функция добавляет слог для каждого экземпляра:

  • В рабочем цикле не- eгласных, а затем нуля более eс
  • An, eкоторая не является частью трейлинга edили ely, за исключением трейлинга tedили deds
  • Трейлинг le

Анализ

Основная идея состоит в том, чтобы считать серии гласных, но это само по себе не очень точно ( [aeiouy]+получается 74% правильных). Основной причиной этого является молчаниеe , которое изменяет предыдущий гласный звук, но не произносится само по себе. Например, слово slateимеет два гласных, но только один слог.

Чтобы справиться с этим, мы вынимаем eиз первой части регулярное выражение и рассматриваем его отдельно. Обнаружение тихих es сложно, но я обнаружил два случая, когда они происходят часто:

  • Как часть трейлинга ed(если это не tedили, dedкак settledили saddled),
  • Как часть трейлинга evy(например lovely)

Эти случаи специально исключены во что бы то ни стало e..

Причина для .in e(?!d$|ly).заключается в том, чтобы потреблять следующий символ, если есть двойной гласный (например, eaили ee), и так, чтобы eв конце слова не учитывались. Однако замыкающая le это обычно произносится, так что добавляется обратно.

Наконец, гласные звуки считаются одним слогом. Хотя это может не всегда иметь место (например curious), часто трудно определить, существует ли несколько слогов. Возьмите iaиз celestialи spatial, как пример.

Тестовая программа

Я действительно не знаю Руби, поэтому я не уверен, насколько хорошо он может быть в гольф. Мне удалось собрать воедино тестовую программу, посоветовавшись с большим количеством 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
источник
Оу, ты сделал такой высокий стандарт. В Python длина кода ровно на 20 символов длиннее, поэтому моя реализация вашего «гласного, за которым следует буква, которой нет e», дает 6638 (7158 правильно)
justhalf
2
@justhalf Это в основном единственная причина, по которой я использую Ruby: PI обычно использует Python для всего остального.
Sp3000
5

Python3, 7935 - 10 * 71 = 7225

Мой быстрый и грязный ответ: посчитайте серии последовательных гласных, но сначала удалите все финальные буквы.

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

После удаления xсимволов «e» это заменяет гласные, а все остальные символы - пробелом. Результат объединяется обратно в строку, а затем разбивается на пробелы. Удобно, пробелы в начале и в конце игнорируются (например, " x xx ".split()дает ["x","xx"]). Следовательно, длина результирующего списка - это число групп гласных.

Исходный 83-байтовый ответ, приведенный ниже, был более точным, потому что он удалял только один символ e в конце. Таким образом, у более нового возникают проблемы с такими словами, как bee; но сокращенный код перевешивает этот эффект.

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

Тестовая программа:

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

Очевидно, это было слишком грязно и недостаточно быстро, чтобы превзойти ответ Ruby на Sp3000. ; ^)

DLosc
источник
->s{s.scan(/([aiouy]|e(?!$))+/).size}оценка 7583. 84% довольно внушительно для чего-то такого простого.
Sp3000
1

Perl, 8145 - 3 * 30 = 7845

Использование списков до недавних коммитов.

#!perl -lp
$_=s/(?!e[ds]?$)[aeiouy]+//g
nutki
источник
Файлы были недавно обновлены. Я посмотрел и не увидел слов, которые вы назвали в 1-слоговом файле.
Sp3000
@ Sp3000, устали. Они были обновлены 7 часов назад в соответствии с тем, что я вижу, и по этой ссылке до сих пор есть эти слова: github.com/nathanmerrill/wordsbysyllables/blob/master/…
nutki
Похоже, @NathanMerrill испортил обновление 7 часов назад: история .
Sp3000
@ Sp3000, спасибо. Я обновляю счет до более старой версии. Эти списки все еще содержат довольно много ошибок, но не так серьезно.
Nutki
0

Python, 5370-10 * 19 = 5180

Эта программа просто предполагает, что более длинные слова означают больше слогов.

lambda x:len(x)/6+1

Программа тестирования, которую я использую:

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
Натан Меррилл
источник
Должны ли мы создать программу или функцию? Ваша не программа, она ничего не выдает при запуске.
Половина
@justhalf Мне нужно что-то, что принимает ввод и производит вывод (даже если этот вывод не STDIO)
Натан Меррилл
Кстати, я не получил 5150 за использование 7, но 4391. В моем тесте лучше использовать len(x)/6вместо этого (5377-190 = 5187).
Justhalf
@justhalf С обновлениями я получаю 5343, но определенно худший результат с len (x) / 6. Я выложу свою тестовую программу.
Натан Меррилл
readlines()включает новую строку в результате. Таким образом, ваш на самом деле (len(x)+1)/7+1. Вы должны использовать read().split('\n')вместо этого. Хотя я получил 5352 за эту формулу.
Justhalf