Ordem alfabética húngara

19

Para aqueles que desejam muito mais desafio do que a antiga ordem alfabética espanhola , vamos dar uma olhada em como o alfabeto húngaro é ordenado.

a, á, b, c, cs, d, dz, dzs, e, é, f, g, gy, h, i, í, j, k, l, ly, m, n, ny, o, ó, ö, õ, p, q, r, s, sz, t, ty, u, ú, ü, v, v, w, x, y, z, zs

na verdade, q, w, xe ynão são usados em palavras húngaras, mas eles são incluídos para loanwords e nomes estrangeiros. Caracteres com sotaque estrangeiro que não fazem parte do alfabeto húngaro (como ñ), têm a mesma prioridade que os sem sotaque, mas os desconsideramos neste desafio.

As regras, resumidas:

  • Dígrafos ( cs, sz, etc.) eo trigraph ( dzs) são considerados como eram letras por conta própria.
cudar
cukor
cuppant
csalit
csata
  • Se o mesmo dígrafo ou trigrama ocorrer duas vezes diretamente um após o outro em uma palavra, eles serão escritos de uma maneira simplificada: em sszvez de szsz, em ddzsvez de dzsdzsmas para a ordem alfabética, a ordem não simplificada é usada. Por exemplo kasza< kaszinó< kassza, porque kasszaé usado como k+ a+ sz+ sz+ apor causa da ordenação. Às vezes, você pode encontrar a versão não contratada em uma palavra, no caso de palavras compostas.
kasza
kaszinó
kassza
kaszt
nagy
naggyá
nagygyakorlat
naggyal
nagyít
  • letras maiúsculas não importa, com exceção das duas palavras exatamente iguais sem letras maiúsculas, caso em que a letra minúscula tem prioridade
jácint
Jácint
Zoltán
zongora
  • As versões curtas e longas de vogais acentuadas têm a mesma prioridade ( a - á, e -é, i - í, o - ó, ö - ő, u - ú ü - ű), com uma única exceção: se as duas palavras de outra forma seria exatamente o mesmo, a vogal curta tem prioridade sobre a vogal longa. Observe que as vogais com trema ( öe ü) são caracteres completamente diferentes de oe u.
Eger
egér
író
iroda
irónia
kerek
kerék
kérek
szúr
szül
  • Hífens ou espaços (por exemplo, em palavras compostas, nomes etc.) são completamente ignorados
márvány
márványkő
márvány sírkő
Márvány-tenger
márványtömb

A tarefa

Seu programa / função recebe seqüências de caracteres, compostas por caracteres do alfabeto húngaro (letras maiúsculas e minúsculas), mas uma sequência pode conter espaços ou hífens. Por uma questão de simplicidade, o sinal de menos (ASCII 45) pode ser usado como um hífen. Observe que alguns caracteres (como o ő) não fazem parte do ASCII. Você pode usar qualquer codificação que desejar, se ela suportar todos os caracteres necessários.

Você precisa ordenar as linhas corretamente e exibir / retornar o resultado.

Você pode usar qualquer subconjunto ordenado aleatoriamente dos exemplos acima para teste.

EDITAR:

Por favor, não use nenhuma maneira interna ou de outra maneira que já conheça a ordem alfabética húngara por si só. Isso tornaria a competição inútil e levaria todo o desafio de encontrar a melhor expressão regular ou os melhores truques de golfe com código.

EDIT2:

Para esclarecer um esclarecimento solicitado por isaacg: "duas cadeias que diferem apenas em maiúsculas e vogais longas versus vogais curtas, mas diferem nos dois sentidos": Embora nenhuma regra no documento oficial lide explicitamente com essa questão, um exemplo encontrado dentro de pontos para o comprimento da vogal tendo mais importância que a capitalização.

vsz
fonte
@FryAmTheEggman Onde você vê isso?
23416 Morgan Thrapp
9
Cara, eu não consigo nem memorizar nossa ordem alfabética adequada. Como vou programar isso? ;)
Andras Deak
11
Estou tentando criar um contra-exemplo vinculado à falha, em que um dígrafo aparente é na verdade duas letras, como malacsültou nyílászáró. Pergunto-me se houver algum (mas você precisa de um vocabulário para verificar se que, o que não é, presumivelmente, parte deste desafio)
Andras Deak
11
Não existe nenhum exemplo contendo dzs
TheConstructor
11
Gramática. Nível: húngaro!
31517 sergiol #

Respostas:

4

Perl, 250

Inclui +11 para -Mutf8 -CS.

use Unicode::Normalize;$r="(?=cs|zs|dz|sz|[glnt]y)";print map/\PC*
/g,sort map{$d=$_;s/d\Kd(zs)|(.)\K$r\2(.)/\L$+\E$&/gi;s/d\Kzs/~$&/gi;s/$r.\K./~$&/gi;s/(\p{Ll}*)(\w?)\s*-*/\U$1\L$2/g;$c=$_;$b=$_=NFD lc;y/̈̋/~~/d;join$;,$_,$b,$c,$d}<>

Usa o idioma decorar-classificar-não decorado (AKA Schwartzian Transform ) e a classificação multinível , onde os níveis são:

  • L1: compare letras base, ignore sinais diacríticos, maiúsculas e minúsculas.
  • L2: compare letras base e diacríticos, ignore maiúsculas e minúsculas.
  • L3: compare letras base, diacríticos e maiúsculas e minúsculas, ignore alguma pontuação.
  • Ln: comparação de nível de bytes de desempate.

Internamente, (ASCII 0x1C Field Separator - cujo valor é menor que qualquer caractere no alfabeto para este desafio) é usado como um separador de nível.

Esta implementação tem muitas limitações, entre elas:

  • Não há suporte para caracteres estrangeiros.
  • Não é possível desambiguar entre dígrafos / trigramas contratados geminados (longos) e consoante + dígrafo / trigrafo, por exemplo: könnyű deve agrupar como <k><ö><ny> <ny> <ű> , enquanto tizennyolc deve agrupar como <t> < i> <z> <e> <n> <ny> <o> <l> <c> ; házszám 'address = número da casa (ház) (szám)' deve ser agrupado como <h><á><z><sz><á> <m> e não como * <h><á><zs> <z> <m> .
  • O agrupamento de dígitos longos contratados não é tão consistente (mas é estável): desambiguamos no nível idêntico ( ssz < n szsz, ..., zszs < n zzs ); glibc agrupa os formulários abreviados antes dos formulários completos ( ssz <szsz, ..., zzs <zszs ), a UTI coleta os formulários longos antes dos formulários abreviados, começando em L3 Case and Variants ( szsz < 3 ssz, ..., zszs < 3 zzs )

Versão expandida:

use Unicode::Normalize;

$r="(?=cs|zs|dz|sz|[glnt]y)";   # look-ahead for digraphs

print map/\PC*\n/g,             # undecorate
  sort                          # sort
  map{                          # decorate

          $d=$_;                # Ln: identical level

          # expand contracted digraphs and trigraphs
          s/d\Kd(zs)|(.)\K$r\2(.)/\L$+\E$&/gi;

          # transform digraphs and trigraphs so they 
          #  sort correctly
          s/d\Kzs/~$&/gi;s/$r.\K./~$&/gi;

          # swap case, so lower sorts before upper
          # also, get rid of space, hyphen, and newline
          s/(\p{Ll}*)(\w?)\s*-*/\U$1\L$2/g;

          $c=$_;                # L3: Case

          $b=$_=NFD lc;         # L2: Diacritics

          # transform öő|üű so they sort correctly
          # ignore diacritics (acute) at this level
          y/\x{308}\x{30b}\x{301}/~~/d;

                                # L1: Base characters
          join$;,$_,$b,$c,$d
  }<>

†. Alguns algoritmos de intercalação de vários níveis conhecidos são o Algoritmo de intercalação Unicode (UCA, Unicode UTS # 10) , ISO 14651 (disponível no site da ISO ITTF ) e as partes LC_COLLATE na ISO TR 30112 (rascunho disponível na ISO / IEC JTC1 / SC35 / WG5 home ) obsoleta a ISO / IEC TR 14652 (disponível na ISO / IEC JTC1 / SC22 / WG20 ) e LC_COLLATE no POSIX.

‡. Fazer isso corretamente exigiria um dicionário. A UTI trata grupos estranhamente capitalizados como não-contrações / não-dígrafos / não-trigrafos, por exemplo: ccS < 3 CcS < 3 c Cs < 3 c CS < 3 C Cs < 3 cS < 3 cs < 3 Cs < 3 CS < 3 ccs < 3 Ccs < 3 CCS

ninjalj
fonte
Você poderá salvar alguns bytes usando minha expansão RegExp.
TheConstructor
6

Java 8, 742 bytes

Pode reduzir em mais 3 bytes nomeando a função em svez de sortou em outros 16 bytes, se não contar a definição de classe.

public class H{String d="cs|dzs?|gy|ly|sz|ty|zs";void sort(java.util.List<String>l){l.sort((a,b)->{String o="-a-á-b-cs-dzs-e-é-f-gy-h-i-í-j-k-ly-m-ny-o-ó-ö-ő-p-q-r-sz-ty-u-ú-ü-ű-v-w-x-y-zs-";int i=c(r(a),r(b),r(o));return i!=0?i:(i=c(a,b,o))!=0?i:b.charAt(0)-a.charAt(0);});}String r(String a){for(int i=0;i<8;i++)a=a.toLowerCase().replace("ááéíóőúű".charAt(i),"aaeioöuü".charAt(i));return a;}int c(String a,String b,String o){a=n(a);b=n(b);while(!"".equals(a+b)){int i=p(a,o),j=p(b,o);if(i!=j)return i-j;a=a.substring(i%4);b=b.substring(j%4);}return 0;}int p(String a,String o){a=(a+1).replaceAll("("+d+"|.).*","-$1");return o.indexOf(a)*4+a.length()-1;}String n(String a){return a.toLowerCase().replaceAll("(.)(?=\\1)("+d+")| |-","$2$2");}}

Pode ser usado assim:

new H().sort(list);

Suíte de teste:

public static void main(String[] args) {
    test(Arrays.asList("cudar", "cukor", "cuppant", "csalit", "csata"));
    test(Arrays.asList("kasza", "kaszinó", "kassza", "kaszt", "nagy", "naggyá", "nagygyakorlat", "naggyal",
            "nagyít"));
    test(Arrays.asList("jácint", "Jácint", "Zoltán", "zongora"));
    test(Arrays.asList("Eger", "egér", "író", "iroda", "irónia", "kerek", "kerék", "kérek", "szúr", "szül"));
    test(Arrays.asList("márvány", "márványkő", "márvány sírkő", "Márvány-tenger", "márványtömb"));
}

private static void test(final List<String> input) {
    final ArrayList<String> random = randomize(input);
    System.out.print(input + " -> " + random);
    new H().sort(random);
    System.out.println(" -> " + random + " -> " + input.equals(random));
}

private static ArrayList<String> randomize(final List<String> input) {
    final ArrayList<String> temp = new ArrayList<>(input);
    final ArrayList<String> randomOrder = new ArrayList<>(input.size());
    final Random r = new Random();
    for (int i = 0; i < input.size(); i++) {
        randomOrder.add(temp.remove(r.nextInt(temp.size())));
    }
    return randomOrder;
}

produzindo

[cudar, cukor, cuppant, csalit, csata] -> [csata, cudar, cuppant, csalit, cukor] -> [cudar, cukor, cuppant, csalit, csata] -> true
[kasza, kaszinó, kassza, kaszt, nagy, naggyá, nagygyakorlat, naggyal, nagyít] -> [naggyá, kassza, kaszinó, nagygyakorlat, nagyít, nagy, kaszt, kasza, naggyal] -> [kasza, kaszinó, kassza, kaszt, nagy, naggyá, nagygyakorlat, naggyal, nagyít] -> true
[jácint, Jácint, Zoltán, zongora] -> [Zoltán, jácint, zongora, Jácint] -> [jácint, Jácint, Zoltán, zongora] -> true
[Eger, egér, író, iroda, irónia, kerek, kerék, kérek, szúr, szül] -> [egér, Eger, kerék, iroda, író, kerek, kérek, szúr, irónia, szül] -> [Eger, egér, író, iroda, irónia, kerek, kerék, kérek, szúr, szül] -> true
[márvány, márványkő, márvány sírkő, Márvány-tenger, márványtömb] -> [márványtömb, márványkő, Márvány-tenger, márvány sírkő, márvány] -> [márvány, márványkő, márvány sírkő, Márvány-tenger, márványtömb] -> true

Ungolfed:

public class HungarianOrder {

    String d = "cs|dzs?|gy|ly|sz|ty|zs";

    void sort(java.util.List<String> l) {
        l.sort((a, b) -> {
            String o = "-a-á-b-cs-dzs-e-é-f-gy-h-i-í-j-k-ly-m-ny-o-ó-ö-ő-p-q-r-sz-ty-u-ú-ü-ű-v-w-x-y-zs-";
            int i = c(r(a), r(b), r(o));
            return i != 0 ? i
                    : (i = c(a, b, o)) != 0 ? i
                            : b.charAt(0) - a.charAt(0);
        });
    }

    // toLower + remove long accent
    String r(String a) {
        for (int i = 0; i < 8; i++)
            a = a.toLowerCase().replace("ááéíóőúű".charAt(i), "aaeioöuü".charAt(i));
        return a;
    }

    // iterate over a and b comparing positions of chars in o
    int c(String a, String b, String o) {
        a = n(a);
        b = n(b);
        while (!"".equals(a + b)) {
            int i = p(a, o), j = p(b, o);
            if (i != j)
                return i - j;
            a = a.substring(i % 4);
            b = b.substring(j % 4);
        }
        return 0;
    }

    // find index in o, then looking if following characters match
    // return is index * 4 + length of match; if String is empty or first character is unknown -1 is returned
    int p(String a, String o) {
        a = (a+1).replaceAll("("+d+"|.).*", "-$1");
        return o.indexOf(a) * 4 + a.length() - 1;
    }

    // expand ddz -> dzdz and such
    String n(String a) {
        return a.toLowerCase().replaceAll("(.)(?=\\1)("+ d +")| |-", "$2$2");
    }
}

Estou usando o Listtipo de Java e a order()função dele, mas o comparador é todo meu.

TheConstructor
fonte
Impressionante! Eu imagino que você deva largar o especificador de tipo de lista <String>e salvar alguns caracteres ao custo de alguns avisos?
Josh
@ Josh nah, produziria dois modelos como Java inferiria Objectcomo tipo de aeb então. Eu provavelmente poderia sair definindo uma extensão de parâmetro genérico de classe String. Também não estou esperando ter o código mais curto. ;-)
TheConstructor
3

Python 3, 70

Economizou 8 bytes graças a shooqie.

Eu amo Python. : D

Espera uma lista de cadeias.

from locale import*;setlocale(0,'hu')
f=lambda x:sorted(x,key=strxfrm)
Morgan Thrapp
fonte
3
Isso não é uma brecha padrão?
vsz 11/03/19
11
@ vsz Não tanto quanto eu sei. O uso de built-ins faz parte de muitos desafios.
Morgan Thrapp 11/03/16
11
@vsz Ele tem uma taxa muito baixa de votos negativos nas postagens de brechas padrão para ser contada como padrão, você teria que proibi-lo explicitamente.
FryAmTheEggman 11/03/16
11
Ok, pronto. Eu considerei proibi-lo explicitamente, mas acho que deveria ser óbvio que isso tornaria todo o desafio um ponto discutível. Sinto muito pelo inconveniente.
vsz 11/03/16
11
from locale import*salva um monte de bytes
shooqie