Як порахувати склади словом


22

Введення: Вам передадуть рядок, що містить одне англійське слово. Усі літери будуть малі, а в рядку не буде буквенних символів.

Вихід: Ви повернете ціле число від 1 до 7, що відображає кількість складів, на вашу думку, у слові.

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

Для створення моєї кількості складів я використав це як список моїх слів, а це - для підрахунку складів.


У 3-складних словах містяться "корчма" та "рубін". Двоскладові слова містять такі: "ір", "руда", "рой", "йєр". Крім цього, списки здаються досить точними.
justhalf

@justhalf дякую за цей улов. Створення списків, безумовно, була найважчою частиною проблеми.
Натан Меррілл


3
Цей виклик змушує мене зрозуміти, наскільки дурною може бути англійська мова. Візьмемо resumeдля прикладу ...
Sp3000

Відповіді:


12

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

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

Це анонімна функція Ruby, яка використовує регулярні вирази для підрахунку складів.

Функція додає склад для кожного примірника:

  • Пробіг eнеголосних з наступним нулем більше es
  • Оно, 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, в якості прикладу.

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

Я насправді не знаю Рубі, тому я не впевнений, наскільки добре це можна пограти в гольф. Мені вдалося скрепити програму тестування, консультувавшись з тим, хоча:

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, ти зробив стандарт таким високим. У 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та інші символи замінюються пробілом. Результат з'єднується назад у рядок, а потім розбивається на пробіл. Зручно, пробіли на початку та в кінці ігноруються (наприклад, " x xx ".split()дає ["x","xx"]). Отже, довжина списку - кількість груп голосних.

Оригінальна, 83-байтна відповідь нижче була більш точною, оскільки вона видалила лише один е в кінці. Таким чином, новіший має проблеми з такими словами 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))

Очевидно, це було занадто брудно і недостатньо швидко, щоб перемогти відповідь Рубі Sp3000. ; ^)


->s{s.scan(/([aiouy]|e(?!$))+/).size}бали 7583. 84% вражає щось таке просте.
Sp3000

1

Perl, 8145 - 3 * 30 = 7845

Використання списків до останніх фіксацій.

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

Файли нещодавно оновлені. Я подивився і не побачив слів, які ви назвали у файлі 1-го складу.
Sp3000

@ Sp3000, норов. Вони там, де оновлено 7 годин тому відповідно до того, що я бачу, і все ще є ті слова під цим посиланням: github.com/nathanmerrill/wordsbysyllables/blob/master/…
nutki

Схоже, @NathanMerrill зіпсував оновлення 7 годин тому: історія .
Sp3000

@ Sp3000, спасибі Я оновлюю оцінку на більш стару версію. Ці списки все ще мають досить багато помилок, але не такі серйозні.
nutki

0

Пітон, 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

@justhalf Мені потрібно щось, що приймає вхід і виробляє вихід (навіть якщо цей вихід не є STDIO)
Nathan Merrill

До речі, я не отримав 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.