Jak liczyć sylaby jednym słowem

22

Dane wejściowe: otrzymasz ciąg zawierający jedno angielskie słowo. Wszystkie litery będą pisane małymi literami, a ciąg nie będzie zawierał znaków innych niż alfabetyczne.

Wyjście: Zwrócisz liczbę całkowitą od 1 do 7 reprezentującą liczbę sylab, które Twoim zdaniem są w tym słowie.

Punktacja: Twój program będzie działał dla wszystkich słów znalezionych w tym repozytorium . Jeśli otrzymujesz Npoprawne słowa, a twój program ma Mbajty duże, to twój wynik toN-(M*10) . Największy wynik wygrywa.

Aby wygenerować moją liczbę sylab, użyłem tego jako mojej listy słów i tego do zliczenia sylab.

Nathan Merrill
źródło
3-sylabowe słowa zawierają „inn” i „ruby”. 2-sylabowe słowa zawierają: „irs”, „ore”, „roy”, „yer”. Poza tym listy wydają się wystarczająco dokładne.
justhalf
@ justhalf dziękuję za te połowy. Utworzenie list było zdecydowanie najtrudniejszą częścią wyzwania.
Nathan Merrill
3
To wyzwanie uświadamia mi, jak głupi może być angielski. Weźmy resumena przykład ...
Sp3000,

Odpowiedzi:

12

Rubinowy, 8618 poprawny (91,1%), 53 bajty, 8618 - 10 * 53 = wynik 8088

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

Jest to anonimowa funkcja Ruby, która używa wyrażeń regularnych do liczenia sylab.

Funkcja dodaje sylabę do każdego wystąpienia:

  • Seria non- esamogłosek, po której następuje zero lub więceje s
  • eKtóry nie częścią tylną edi ely, z wyjątkiem końcowe tedlubded S
  • Wleczenie le

Analiza

Podstawową ideą jest zliczanie samogłosek, ale samo to nie jest zbyt dokładne ( [aeiouy]+uzyskuje 74% poprawności). Głównym tego powodem jest cicha zmianae , która modyfikuje poprzednią samogłoskę, ale sama nie jest wymawiana. Na przykład słowoslate ma dwie samogłoski, ale tylko jedną sylabę.

Aby sobie z tym poradzić, wyjmujemy epierwszą część wyrażenia regularnego i traktujemy ją osobno. Wykrywanie cichych es jest trudne, ale znalazłem dwa przypadki, w których często występują:

  • Jako część tylną ed(o ile nie jest to tedlub dedpodobne settledlubsaddled )
  • W ramach końcowego evy(np. lovely)

Przypadki te są wyraźnie wykluczone z tego, co byłoby inaczej e..

Powodem .in e(?!d$|ly).jest użycie następnego znaku, jeśli występuje podwójna samogłoska (np. eaLub ee), a więc ena końcu słowa nie są liczone. Jednak końcowe le jest zwykle wymawiane, więc jest dodawane z powrotem.

Wreszcie, samogłoski są liczone jako jedna sylaba. Chociaż nie zawsze tak jest (np. curious), Często trudno jest ustalić, czy istnieje wiele sylab. Weź iaod celestialispatial , jako przykład.

Program testowy

Naprawdę nie znam Ruby, więc nie jestem pewien, jak dobrze można grać w golfa. Udało mi się zeskrobać program testowy, konsultując wiele 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
źródło
Aww, uczyniłeś ten standard tak wysokim. W Pythonie długość kodu jest dokładnie 20 znaków dłuższa, więc moja implementacja „samogłoski, po której następuje litera, która nie jest e” daje 6638 (poprawne 7158)
pół
2
@ justhalf Jest to w zasadzie jedyny powód, dla którego używam Ruby: PI zwykle używa Pythona do wszystkiego innego.
Sp3000,
5

Python3, 7935 - 10 * 71 = 7225

Moja szybka i brudna odpowiedź: policz serie kolejnych samogłosek, ale najpierw usuń wszystkie końcowe e.

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

Po usunięciu liter e zastępuje samogłoski xi wszystkie inne znaki spacją. Wynik jest ponownie łączony w ciąg, a następnie dzielony na białe znaki. Dogodnie spacje na początku i na końcu są ignorowane (np. " x xx ".split()Daje ["x","xx"]). Długość wynikowej listy jest zatem liczbą grup samogłosek.

Oryginalna, 83-bajtowa odpowiedź poniżej była dokładniejsza, ponieważ usunęła tylko jeden e na końcu. Nowszy ma zatem problemy z takimi słowami bee; ale skrócony kod przeważa nad tym efektem.

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

Program testowy:

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

Najwyraźniej było to zbyt brudne i zbyt szybkie, aby pobić odpowiedź Ruby na Sp3000. ; ^)

DLosc
źródło
->s{s.scan(/([aiouy]|e(?!$))+/).size}zdobywa 7583. 84% jest imponujące jak na coś tak prostego.
Sp3000,
1

Perl, 8145 - 3 * 30 = 7845

Korzystanie z list sprzed ostatnich zatwierdzeń.

#!perl -lp
$_=s/(?!e[ds]?$)[aeiouy]+//g
nutki
źródło
Pliki zostały ostatnio zaktualizowane. Spojrzałem i nie zobaczyłem słów, które nazwałeś w pliku 1 sylaby.
Sp3000,
@ Sp3000, zużyte. Zostały zaktualizowane 7 godzin temu zgodnie z tym, co widzę, i nadal są te słowa pod tym linkiem: github.com/nathanmerrill/wordsbysyllables/blob/master/…
nutki
Wygląda na to, że @NathanMerrill pomieszał aktualizację 7 godzin temu: historia .
Sp3000
@ Sp3000, dzięki. Aktualizuję partyturę do starszej wersji. Na tych listach wciąż jest sporo błędów, ale nie tak poważne.
nutki
0

Python, 5370-10 * 19 = 5180

Ten program zakłada po prostu, że dłuższe słowa oznaczają więcej sylab.

lambda x:len(x)/6+1

Program testowy, którego używam to:

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
źródło
Czy powinniśmy stworzyć program czy funkcję? Twój nie jest programem, nie uruchamia nic po uruchomieniu.
justhalf
@ justhalf Potrzebuję czegoś, co akceptuje dane wejściowe i generuje dane wyjściowe (nawet jeśli dane wyjściowe nie są STDIO)
Nathan Merrill
Przy okazji nie dostałem 5150 za użycie 7, ale 4391. W moim teście lepiej jest użyć len(x)/6zamiast tego (5377-190 = 5187).
justhalf
@ justhalf Dzięki aktualizacjom otrzymuję 5343, ale zdecydowanie uzyskuję gorszy wynik dzięki len (x) / 6. Zamieszczę mój program testowy.
Nathan Merrill
readlines()zawiera nowy wynik w wyniku. Więc twoje jest w rzeczywistości (len(x)+1)/7+1. Zamiast tego powinieneś użyć read().split('\n'). Chociaż dostałem 5352 dla tej formuły.
justhalf