Você é um romanizador, baby

38

A romanização do japonês está convertendo o texto japonês em caracteres latinos. Neste desafio, você receberá uma sequência de caracteres japoneses como entrada e espera-se convertê-los na sequência ASCII correta.

O que você precisa saber

O idioma japonês possui três sistemas de escrita: hiragana (o curvy usado para palavras curtas), katakana (o ângulo y usado para sons e palavras emprestados de outras línguas) e kanji (os caracteres densos originalmente do chinês). Neste desafio, apenas nos preocuparemos com hiragana.

Existem 46 caracteres no silabário hiragana. Cada personagem representa uma sílaba. Os caracteres são organizados por primeiro som (consoante) e segundo som (vogal). As colunas em ordem são aiueo.

 : あいうえお
k: かきくけこ
s: さしすせそ
t: たちつてと
n: なにぬねの
h: はひふへほ
m: まみむめも
y: や ゆ よ
r: らりるれろ
w: わ   を
N: ん

(se você copiar e colar esta tabela, observe que usei os espaços ideográficos U + 3000 para espaçar y e w)

Então, por exemplo, あ と め deve produzir uma saída de atome. O primeiro caractere é a, o segundo é toe o terceiro é me.

Exceções

Como qualquer bom idioma, o japonês tem exceções às suas regras, e a tabela hiragana possui várias. Esses caracteres são pronunciados de maneira ligeiramente diferente do que sua localização na tabela implicaria:

し: shi, não si
ち: chi, não ti
つ: tsu, não tu
ふ: fu, nãohu

Dakuten ゛

A palavra 'dakuten' significa 'marca enlameada': o dakuten transforma sons em seus equivalentes sonoros (geralmente); por exemplo, か se katransforma em か ゛ga. Uma lista completa das alterações:

kg
sz
td
hb

As exceções também mudam: し ゛: ji(ou zhi), não zi
゛ ゛: ji, não di
つ ゛: dzu, not du
(ふ ゛ age como você esperaria; não é uma exceção)

O handakuten é um caractere adicional゜ que se aplica à hlinha. Se colocado após um personagem, ele altera o som do personagem para em pvez de b.

Tanto o dakuten quanto o handakuten serão dados como caracteres individuais. Você não precisará lidar com os formulários pré-compostos ou os caracteres combinados.

Personagens pequenos

Finalmente, existem pequenas versões de alguns dos personagens. Eles modificam caracteres que vêm antes ou depois deles.

ゃ ゅ ょ

Estas são as pequenas formas de ya, yue yo. Eles são colocados somente após sons na icoluna-; eles removem ie adicionam seu som. Então, や や se transforma kiya; ゃ ゃ se transforma kya.

Se colocado após chiou shi(ou suas formas dakuten-ed), o também yserá removido. ゆ ゆ é shiyu; ゅ é shu.

A última coisa com a qual você terá que lidar é com as pequenas tsu. っ duplica a consoante que vem depois, não importa o quê; não faz mais nada. Por exemplo, き た é kita; た っ た é kitta.

Resumo, Entrada e Saída

Seu programa deve ser capaz de transliterar: os 46 hiragana básicos, suas formas de dakuten e handakuten e suas combinações com caracteres pequenos.

O comportamento indefinido inclui: pequeno ya, yue yonão após um caractere com i, pequeno tsuno final de uma string, dakuten em um personagem não afetado, handakuten em um não pcaractere e qualquer outra coisa não mencionada na especificação / introdução acima.

Você pode assumir que todas as entradas são válidas e contêm apenas os caracteres japoneses mencionados acima.

Case não importa na saída; você também pode substituir rpor lou solitário npor m. A saída pode ter um espaço entre cada sílaba ou nenhum espaço.

Este é o : o código mais curto em bytes vence.

Casos de teste

Muitos casos de teste para cada parte individual são fornecidos nas especificações. Alguns casos adicionais:

ひ ら か ゛ な → hiragana

な た か な → katakana

た ゛ い き ゛ く て ん さ い は ゛ → daigyakutensaiban

ふ ゜ ろ く ゛ み ん く は ゜ す ゛ こ う と ゛ ふ → puroguramingupazurucoudogorufu

か ゛ ん ほ ゛ っ → ganbatte

Notas

  • Não sei muito japonês além do que escrevi aqui. Informe-me se cometi algum erro.

  • Originalmente, eu planejava incluir katakana também (para que meu caso de teste de transliteração em inglês pudesse ser um pouco mais preciso), mas isso seria demais para um desafio de golfe com código.

  • Os nomes Unicode incluem a transliteração de cada caractere individualmente, mas sem as exceções. Isso pode ou não ser útil para você.

  • Obrigado ao squeamishossifrage por corrigir dois erros de digitação!

  • Me desculpe se isso for muito longo; Tentei encaixar a maioria das peculiaridades da hiragana no desafio, mas algumas coisas (como hiragana apenas com vogais pequenas, alterar n para m na frente de algumas consoantes e a marca de repetição) tiveram que ser cortadas para manter o desafio administrável.

  • Não sinto muito pelo título. É uma obra-prima.

Deusovi
fonte
1
Qual deve ser a saída きっった?
lirtosiast
@ Thomas: Essa é uma entrada inválida. A saída pode ser o que você quiser.
Deusovi 29/11
1
deve っしser sshiou shshi?
lirtosiast
2
I'm not at all sorry for the title. It's a masterpiece.Downvoted
Fatalize
3
@Fatalize Não há necessidade de trazer seu viés anti-Britney aqui. Mesmo que eu pessoalmente seja mais fã de J-Lo, não vou votar um excelente quebra-cabeça sobre isso.
semi-extrínseco

Respostas:

7

Python 2, 638 bytes

import unicodedata
s=input()
k=[0x309B,0x309C,0x3063]
m=[0x3083,0x3085,0x3087]
e={0x3057:'shi',0x3061:'chi',0x3064:'tsu',0x3075:'fu'}
d={0x3057:'ji',0x3061:'ji',0x3064:'dzu'}
D=dict(zip('ksth','gzdb'))
f=lambda c:unicodedata.name(c).split()[-1].lower()if ord(c)not in e else e[ord(c)]
g=lambda c:d[c]if c in d else D[f(c)[0]]+f(c)[1:]
R=[]
r=[]
t=[]
i=0
while i<len(s):
 c=ord(s[i])
 if c==k[0]:R[-1]=g(s[i-1])
 elif c==k[1]:R[-1]='p'+R[-1][1:]
 elif c in m:R[-1]=R[-1][:-1];n=f(s[i]);R+=[n[1:]]if r[-1]in[0x3057,0x3061]else[n];r+=[c]
 elif c==k[2]:t+=[len(R)]
 else:R+=[f(s[i])];r+=[c]
 i+=1
for i in t:R[i]=R[i][0]+R[i]
print ''.join(R)

Recebe a entrada como uma string unicode.

Teste no Ideone

TFeld
fonte
1
Você pode salvar um bye míseros mudando print ''.join(R)paraprint''.join(R)
Zachary
6

Python 2, 447 bytes

import unicodedata as u
r=str.replace
i=''.join('x'*('SM'in u.name(x)or ord(x)==12444)+u.name(x)[-2:].strip()for x in raw_input().decode('utf-8'))
for a,o in zip('KSTH','GZDB'):
    for b in'AEIOU':i=r(r(i,a+b+'xRK','P'+b),a+b+'RK',o+b)
for a,b,c,d in zip('STDZ',('SH','CH','J','J'),'TDHH',('TS','DZ','F','F')):i=r(r(i,a+'I',b+'I'),c+'U',d+'U')
for a in'CH','SH','J':i=r(i,a+'IxY',a)
for a in'BCDFGHJKMNPRSTWYZ':i=r(i,'xTSU'+a,a+a)
print r(i,'Ix','')

Isso leva a entrada Unicode diretamente, o que me fez perder alguns bytes por causa do, decode('utf-8')mas acho que está mais no espírito do desafio.

Comecei substituindo cada personagem pelos dois últimos caracteres de seu nome unicode, conforme sugerido nas notas do quebra-cabeça. Infelizmente, isso não faz distinção entre versões alternativas do mesmo personagem, então tive que fazer um truque feio para adicionar um 'x' antes dos caracteres pequenos e do handakuten.

O restante dos loops for está apenas corrigindo exceções, em ordem:

  1. o primeiro para loop transforma dakutens e handakutens nas consoantes corretas;
  2. o segundo para loop lida com as exceções hiragana de shi, chi, tsu e fu;
  3. o terceiro para o loop lida com as exceções antes de um pequeno caractere y (como sha, jo);
  4. o quarto for loop lida com consoantes dobradas após um pequeno tsu.
  5. a linha final lida com y pequeno.

Eu gostaria de poder ter combinado mais etapas, mas, em alguns casos, as etapas precisam ser executadas para evitar conflitos.

Experimente online! (uma versão multilinha com mais exemplos pode ser encontrada aqui ).

ffao
fonte
1
TIO link
boboquack
Bem-vindo ao PPCG. Primeira solução muito agradável :)
Shaggy
Transforme seus quatro espaços na frente for b in'AEIOU'em uma guia ou um único espaço para economizar 3 bytes. Você também pode usar from unicodedata import*para salvar alguns bytes - não tenho certeza.
Stephen
4

Swift 3, 67 64 caracteres

deixe r = {(s: String) em s.applyingTransform (.toLatin, reverse: false)}

let r={(s:String)in s.applyingTransform(.toLatin,reverse:false)}
idrougge
fonte
3
A built-in, realmente, Swift tem um construtor para isso?
Zacharý
Não conheço o Swift, mas você pode cortar os espaços em branco depois s:String)e .toLatin,?
Yytsi 03/08/19
@TuukkaX, bem visto!
Idragge
@ Zacharý, bem Foundationtem.
Idragge
3

Python 3 , 259 bytes

import re,unicodedata as u
s=re.sub
n=u.normalize
k,*r=r'NFKC DZU DU TSU TU \1\1 SM.{6}(.) \1 (CH|J|SH)Y \1 ISMALL.(Y.) CHI TI JI [ZD]I SHI SI FU HU'.split()
t=''.join(u.name(c)[16:]for c in n(k,s(' ','',n(k,input()))))
while r:t=s(r.pop(),r.pop(),t)
print(t)

Experimente online!

Explicação

Estamos com sorte com este formato de entrada! Veja o que acontece se eu passar a entrada pela normalização do NFKC :

>>> nfkc = lambda x: u.normalize('NFKC', x)
>>> [u.name(c) for c in 'は゛']
['HIRAGANA LETTER HA', 'KATAKANA-HIRAGANA VOICED SOUND MARK']
>>> [u.name(c) for c in nfkc('は゛')]
['HIRAGANA LETTER HA', 'SPACE', 'COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK']

O dakuten é substituído por um espaço e um dakuten combinado. Agora esse espaço é tudo o que separa o は do seu dakuten. Então nos livramos e normalizamos novamente :

>>> [u.name(c) for c in nfkc(nfkc('は゛').replace(' ', ''))]
['HIRAGANA LETTER BA']

Bingo. A quinta linha transforma a entrada em algo como

KONOSUBARASIISEKAINISISMALL YUKUHUKUWO

Em seguida, aplicamos 9 substituições regex chatas r, e terminamos:

KONOSUBARASHIISEKAINISHUKUFUKUWO

(Jonathan French salvou 4 bytes, escrevendo em import re,unicodedata as uvez de import re;from unicodedata import*. Obrigado!)

Lynn
fonte
Abusando da normalização por diversão e lucro. Isso é bonito.
Tim Pederick
2
import re,unicodedata as ucomo em Kirill L., a resposta a um desafio relacionado economiza 4 bytes .
Jonathan Frech