Zgadnij, jak wymówić niemieckie słowa

37

Wprowadzenie

W przeciwieństwie do angielskiego, niemiecki jest uważany za dość foniczny system pisania . Oznacza to, że zgodność pisowni z wymową jest bliska. Biorąc pod uwagę każde słowo, którego nie znasz, nadal będziesz wiedział, jak wymówić je ze względu na system pisowni. Oznacza to, że komputer powinien być w stanie zrobić to zbyt dobrze?

Wyzwanie

Napisz program lub funkcję, która pobiera jako ciąg znaków słowo niemieckie i wypisuje lub zwraca swoją wymowę w międzynarodowym alfabecie fonetycznym (IPA) .

Oczywiście nie zamierzam zmuszać cię do nauki niemieckiego ani pełnego IPA . Ta jedna sekcja w Wikipedii zawiera prawie wszystkie reguły niemieckie do IPA, których potrzebujesz, a ja kodowałem implementację referencji C # bez golfisty .

W tym linku znajduje się również lista 400 popularnych niemieckich słów i ich wymowa IPA (wymagana do weryfikacji). Biorąc przykład z tej listy, jeśli dane wejściowe są solltest, poprawne dane wyjściowe to ˈzɔltəst.

Implementacja referencyjna dodaje dwie pomocne reguły niewymienione w sekcji Wikipedii: Zakłada, że ​​stres słowa występuje na pierwszej sylabie (najprawdopodobniej w języku niemieckim) i wykorzystuje lepszą heurystykę do określania, kiedy litera „e” reprezentuje dźwięk schwa / ə /. Implementuje również specjalne przetwarzanie prefiksów, ale nie poprawiło to wyników tak bardzo, jak myślałem.

Detale

Aby zostać uznanym za prawidłowy wpis, Twój program musi spełniać następujące wymagania:

  • Dane wyjściowe IPA muszą być dokładnie dopasowane dla co najmniej 300 z 400 słów na liście słów referencyjnych (implementacja referencyjna otrzymuje poprawną 333)
  • Twój program musi odgadnąć każde wiarygodne niemieckie słowo. Mamy więc wymaganie techniczne, co oznacza, że ​​dla każdego wejścia, które pasuje do wyrażenia regularnego [a-zA-ZäÄöÖüÜ][a-zäöüß]*i ma co najmniej jedną samogłoskę (aeiouyäöü), musisz wygenerować wyjście nie zawierające wyłącznie białych znaków i nie popełnić błędu.
  • Program musi być deterministyczny (zawsze produkować to samo wyjście przy tych samych danych wejściowych)
  • W przeciwnym razie standardowe luki są zabronione (zwłaszcza ta dotycząca pobierania zasobów poza witryną)

Różne rzeczy, które możesz robić:

  • W razie potrzeby umieść początkowe i końcowe białe spacje na wydruku
  • Użyj dowolnego wcześniej istniejącego kodowania znaków w danych wyjściowych (nie wyobrażam sobie, że nic innego niż Unicode działa dobrze, ale jeśli możesz, gratulacje)
  • Załóżmy, że dane wejściowe są w jakiejś znormalizowanej formie, takiej jak formularze normalizacyjne Unicode NFD, NFC itp. Na przykład: ä jest zapisany jako pojedynczy znak lub znak podstawowy + znak łączący?
  • Użyj standardowych metod wejścia i wyjścia

Punktacja i postacie IPA

Punktacja jest w bajtach. Ostrzegamy, że znaki niemieckie i znaki IPA mają 2 bajty w UTF-8. Ponadto, znak IPA U + 0327 ŁĄCZENIE ODWRÓCONEJ KRWI PONIŻEJ (̯) jest znakiem łączącym Unicode i jest 2-bajtowym znakiem UTF-8 samodzielnie. Oznacza to, że coś takiego jak ɐ̯ liczy się jako 4 bajty w UTF-8. Dla ciekawskich ten symbol oznacza, że ​​samogłoska nie tworzy jądra sylaby (poprzednia zamiast tego).

Uważaj również na te znaki IPA, które w niektórych czcionkach wyglądają jak inne znaki ASCII: ɡ, ɪ, ʏ, ː (oznacza długą samogłoskę), ˈ (znaki, które sylaba ma akcent w słowie wielowarstwowym).

Jak utworzono listę słów referencyjnych

Ta sekcja zawiera dodatkowe informacje, które nie są potrzebne do wyzwania.

Lista słów została pobrana z tej Wikisłownikowej listy częstotliwości , usuwając powtórzenia z powodu różnicy wielkości liter i dwóch słów, które nie miały niemieckich wpisów w Wikisłowniku Angielskim (oh i hej). IPA patrzyło zarówno na angielski, jak i na niemiecki Wikisłownik. Tam, gdzie oferowano wiele wymowy, wybrałem bardziej formalną i standardową. Jeśli nie było to jasne, wybrałem ten, który najlepiej pasuje do ogólnych zasad.

Musiałem również ustandaryzować sposób wymawiania litery „r”. W dużym stopniu zależy to od regionu, w jaki sposób wymawiana jest ta litera, a Wikisłownik wcale nie był konsekwentny w tym, który wybrał. Czułem, że zmierza w kierunku: „r” jest wymawiane / ɐ̯ / po którym następuje długa samogłoska, a samogłoska nie następuje, w przeciwnym razie jest to ʁ. Zmieniłem więc wszystkie, aby stosować tę regułę, z wyjątkiem prefiksów ver i er, które były dość konsekwentne / (f) ɛɐ̯ /. Podobnie ustandaryzowałem „eu” jako / ɔʏ̯ /.

DPenner 1
źródło
16
Mathematica ma wbudowaną funkcję ( #~WordData~"PhoneticForm"&), ale działa tylko dla angielskich słów.
JungHwan Min
29
@JungHwanMin Twój komentarz czytam w następujący sposób: Natychmiastowy atak serca, westchnienie ulgi.
DPenner1
1
Skąd mam wiedzieć, że „gestern” jest wymawiane jako „GHES-tern” zamiast „ge-SHTERN”? „bester” jako „BEST-er”, a nie „be-SHTER”?
Leaky Nun
@LeakyNun Nie ma na to 100% algorytmu, ale twoja implementacja potrzebuje tylko 75%. W mojej referencyjnej implementacji również te słowa są błędne.
DPenner1
@LeakyNun Cóż, twój program będzie również w stanie radzić sobie z niemieckimi dialektami, więc jest bardziej wydajny.
P. Siehr,

Odpowiedzi:

9

PHP, 3311 2988 2916 2845 2759 2671 2667 2509 2484 bajtów, przekazując 301/400

<?$f=fopen(__FILE__,r);fseek($f,__COMPILER_HALT_OFFSET__);eval(strtr(stream_get_contents($f),[F=>'=>',M=>'==','&'=>'&&',H=>'function ',A_=>'array',G=>'if',4=>'for','|'=>'||','~'=>'))','%'=>str,7=>'=$',8=>'[]',9=>'!$','@'=>'count(','#'=>';$',5=>'return ',3=>':(']));__halt_compiler();define(J,[ieh,ah,aa,Ah,eh,ee,ie,ih,oh,oo,Oh,uh,Uh,au,eu,Au,ei,ai,ey,ay,a,e,i,o,u,A,O,U,y])#b7e=8;Hv($a){5in_A_($a,J);}Hn($a){5!v($a);}Hpronounce($w){global$b,$e#w=%tr(%tolower(%tr($w,[ßF1,ÄF2,äF2,ÖF0,öF0,ÜF6,üF6]~,[1FS,2FA,0FO,6FU])#W=8#L7w;while($L)4each(A__merge([tzsch,dsch,tsch,zsch,sch,chs,ch,ck,dt,ng,nk,pf,ph,qu,ss,th,tz,b,c,d,f,g,h,j,k,l,m,n,p,r,s,S,t,v,w,x,z],J)as$c){$l=%len($c);G(sub%($L,0,$l)M$c){$W87c#L=sub%($L,$l);break;}}$s=8#l=@$W);4($o7t7i=0#i<$l#i++){$c7W[$i]#p7i?$W[$i-1]:0#n7iM$l-1?0:$W[$i+1];G(9n|!(n($c)&$cM$n&n($W[$i+2]~)$s[$o]87c;G($p&((9n&v($c)&n($p~|(n($n)&v($W[$i+2]~~$s[++$o]=8;}$s[@$s)-1]|A__pop($s);4each($s as$z){$b87t#t+=@$z)#e87t;}$o=[sieFziQ,duFduQ,'die'FdiQ,derFdeQT,zuFtsuQ,wirFviQT,mirFmiQT,denFdeQn,dassFdas,erFeQT,soFzoQ,warFvaQT,fürFfyQT,jaFjaQ,wieFviQ,dirFdiQT,nurFnuQT,demFdeQm,ihnFiQn,auchFaUBx,ihrFiQT,daFdaQ,schonFʃoQn,wennFvEn,malFmaQl,gutFguQt,nachFnaQx,willFvIl,mussFmUs,habFhaQp,vorFfoQT,ihmFmiQm,tunFtuQn][$w]?:'';G($o)goto x#P7B7S7V7Z=0;@$s)>1&$o=[verFfET,daFda,geFgC][join($s[0])]#o&$P=1&A__shGt($s);(($P|@$s)M2)&$o.=W)|(@$s)>2&$d=1&$h=(int)@$s)/2)#w=A__merge(...$s);4each($w as$l){G(0<$S--)continue#n7w[$B+1]#p7w[$B-1]#f=''#Z+=in_A_($B,$b)#f7lMd&9n?t3$lMb&(9n|$nMt)?p3$lMg&(9n|$nMt)?((9n&$pMi)?K:k)3$lMc?(($nMA|$nMe|$nMi)?ts:k)3$lMch?(($pMa|$pMo|$pMu)?x:K)3$lMchs|$lMx?ks3$lMck?k3$lMdsch?dZ3$lMdt|$lMth?t3$lMph|$lMv?f39f&$lMg?g3$lMh?(v($n)?h:'')3$lMng?N3$lMnk?Nk3$lMqu?kv3$lMr?((!v($n)&9nMt)?T:R)3$lMsch?S3$lMss|$lMS?s3$lMtsch|$lMtzsch|$lMzsch?tS3$lMtz|$lMz?ts3$lMw?v3$lMs?(9p&($nMp|$nMt~?S3v($n)?z:s):$f~~~~~~~~~~)#U=0;G(v($l~{G(%len($l)>1)($f=[auFaUB,euFcYB,eiFaIB][$l])|$U=1;else{G(n($n)&((9w[$B+2]&$n!=n)|v($w[$B+2]~)$U=1;G($lMe){$U=9n?:$U;G(9w[$B+2]){G($nMr)($f=A)&$U=9S=1;G($nMm|$nMl)$f=C;}}elseG($nMch)$U=0;G(in_A_($B,$e~$U=0;}$f=($U|9Z)&9f?($l[0]MO?D3$l[0]MU?y3$l[0]MA?E:$l[0]~).Q39f?($lMe?((9n|(9w[$B+2]&($nMn|$nMs~)?C:E)3$lMA?E3$lMi?I3$lMo?c3$lMu?U3($lMU|$lMy)?Y:$l~~~:$f)#V++;}$f7f?:$l;G($d&$ZM$h)$f.=W#o.7f#B++;}G(%pos($o,W)M=false&$V>1)$o=W.$o;4(#j++<%len($o);)G($o[$j]M$o[$j+1])$o=sub%($o,0,$j).sub%($o,$j+1);x:5%tr($o,[SFʃ,ZFʒ,KFç,gFɡ,NFŋ,QF'ː',WFˈ,TFɐ̯,BF'̯',RFʁ,AFɐ,EFɛ,OFœ,IFɪ,YFʏ,UFʊ,cFɔ,CFə,DFø]);}

Definiuje pronounce(string $word).

Stosowanie:

assert(
    pronounce('darüber') == "daˈʁyːbɐ"
);

Jedna uwaga: 3 prefiksy i 33 słowa są zakodowane na stałe, a część kodu jest nieco zoptymalizowana w kierunku listy testów.

Kod testowy jest tutaj , choć to zależy od tego pliku .

Testować:

php test.php all

Napędzany łzami potrójnych oświadczeń.

EDYCJA 7 : Wyciśnięto ~ 170 bajtów, pisząc preprocesor w programie. W rezultacie, rzeczywisty program (wszystko po nim __halt_compiler();) jest trochę trudny do odczytania. Jeśli chcesz nieprzetworzony program, przełącz się evalza printpomocą trzeciej instrukcji.

Élektra
źródło
To w rzeczywistości 2667 bajtów, a nie 2671 (przy założeniu UTF-8)
Cairney Coheringaahing