Orden alfabético húngaro

19

Para aquellos que desean muchos más desafíos que el antiguo orden alfabético español , echemos un vistazo a cómo se ordena el alfabeto húngaro.

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, w, x, y, z, zs

En realidad, q, w, xy yno se utilizan en las palabras de Hungría, pero se incluyen para préstamos y nombres extranjeros. Los caracteres acentuados extranjeros que no forman parte del alfabeto húngaro (como ñ) tienen la misma prioridad que los no acentuados, pero los ignoramos para este desafío.

Las reglas, resumidas:

  • Dígrafos ( cs, sz, etc.) y el trigraph ( dzs) se consideran como estaban las letras por su cuenta.
cudar
cukor
cuppant
csalit
csata
  • Si el mismo dígrafo o trigrafo se produce dos veces directamente uno detrás del otro en una palabra, se escriben de manera simplificada: en sszlugar de szsz, en ddzslugar de dzsdzspero para el orden alfabético, se usa el orden no simplificado. Por ejemplo kasza< kaszinó< kassza, porque kasszase utiliza como k+ a+ sz+ sz+ apor el bien de pedido. A veces puede encontrar la versión no contratada en una palabra, en caso de palabras compuestas.
kasza
kaszinó
kassza
kaszt
nagy
naggyá
nagygyakorlat
naggyal
nagyít
  • las mayúsculas no importan, con la excepción de que las dos palabras serían exactamente iguales sin mayúsculas, en cuyo caso la letra minúscula tiene prioridad
jácint
Jácint
Zoltán
zongora
  • Las versiones corta y larga de vocales acentuadas tienen la misma prioridad ( a - á, e -é, i - í, o - ó, ö - ő, u - ú ü - ű), con una sola excepción: si las dos palabras de otro modo sería exactamente el mismo, la vocal corta tiene prioridad sobre la vocal larga. Tenga en cuenta que las vocales con diéresis ( öy ü) son caracteres completamente diferentes de oy u.
Eger
egér
író
iroda
irónia
kerek
kerék
kérek
szúr
szül
  • Los guiones o espacios (por ejemplo, en palabras compuestas, nombres, etc.) se ignoran por completo
márvány
márványkő
márvány sírkő
Márvány-tenger
márványtömb

La tarea

Su programa / función recibe cadenas, compuestas de caracteres del alfabeto húngaro (minúsculas y mayúsculas), pero una cadena puede contener espacios o guiones. Por simplicidad, el signo menos (ASCII 45) puede usarse como un guión. Tenga en cuenta que algunos caracteres (como el ő) no son parte de ASCII. Puede usar cualquier codificación que desee, si es compatible con todos los caracteres requeridos.

Debe ordenar las líneas correctamente y mostrar / devolver el resultado.

Puede usar cualquier subconjunto ordenado al azar de los ejemplos anteriores para realizar pruebas.

EDITAR:

Por favor, no utilice ninguna forma integrada u otra que ya conozca el orden alfabético húngaro por sí mismo. Haría que la competencia no tuviera sentido y tomaría todo el desafío de encontrar la mejor expresión regular o los mejores trucos de golf de código.

EDIT2:

Para aclarar una aclaración solicitada por isaacg: "dos cadenas que solo difieren en mayúsculas y vocales largas vs. cortas, pero que difieren en ambos sentidos": aunque ninguna regla en el documento oficial aborda explícitamente esta pregunta, un ejemplo encontrado dentro de los puntos de la longitud de la vocal que tiene más importancia que la capitalización.

vsz
fuente
@FryAmTheEggman ¿Dónde ves eso?
Morgan Thrapp
99
El hombre, que ni siquiera puede memorizar nuestra orden alfabético adecuado. ¿Cómo voy a programar esto? ;)
Andras Deak
1
He estado tratando de encontrar un contraejemplo de límite a fracaso, donde un digrafo aparente es en realidad dos letras, como malacsülto nyílászáró. Me pregunto si hay alguno (pero necesitarías un vocabulario para comprobarlo, lo que presumiblemente no forma parte de este desafío)
Andras Deak
1
No hay ningún ejemplo que contenga
dzs

Respuestas:

4

Perl, 250

Incluye +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}<>

Utiliza la expresión decorar-ordenar-decorar (AKA Schwartzian Transform ) y la clasificación multinivel , donde los niveles son:

  • L1: compare letras base, ignore los signos diacríticos, mayúsculas y algunos signos de puntuación.
  • L2: compare letras base y diacríticos, ignore mayúsculas y minúsculas.
  • L3: compare letras base, diacríticos y mayúsculas, ignore algunos signos de puntuación.
  • Ln: comparación de nivel de bytes de desempate.

Internamente, (ASCII 0x1C Field Separator - cuyo valor es menor que cualquier carácter en el alfabeto para este desafío) se usa como un separador de nivel.

Esta implementación tiene muchas limitaciones, entre ellas:

  • No hay soporte para caracteres extranjeros.
  • No se puede desambiguar entre los dígrafos / trigrafos geminados (largos) contraídos y las consonantes + dígrafos / trigrafos, por ejemplo: könnyű debe compaginarse como <k><ö><ny> <ny> <ű> , mientras que tizennyolc debe compaginarse como <t> < i> <z> <e> <n> <ny> <o> <l> <c> ; házszám 'address = house (ház) number (szám)' debe compaginarse como <h><á><z><sz><á> <m> y no como * <h><á><zs> <z> <á> <m> .
  • La clasificación para los dígrafos largos contratados no es tan consistente (pero es estable): desambiguamos al mismo nivel ( ssz < n szsz, ..., zszs < n zzs ); glibc clasifica las formas cortas antes de las formas completas ( ssz <szsz, ..., zzs <zszs ), ICU clasifica las formas largas antes de las formas cortas que comienzan en L3 Caso y Variantes ( szsz < 3 ssz, ..., zszs < 3 zzs )

Versión ampliada:

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

†. Algunos algoritmos de clasificación multinivel conocidos son el Algoritmo de clasificación Unicode (UCA, Unicode UTS # 10) , ISO 14651 (disponible en el sitio ISO ITTF ), las partes LC_COLLATE en ISO TR 30112 (borrador disponible en ISO / IEC JTC1 / SC35 / WG5 home ) que obsoleta ISO / IEC TR 14652 (disponible en ISO / IEC JTC1 / SC22 / WG20 home ) y LC_COLLATE en POSIX.

‡. Hacer esto correctamente requeriría un diccionario. La UCI trata los grupos con mayúsculas extrañas como no contracciones / no digráficos / no trigráficos , por ejemplo: 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
fuente
Debería poder guardar algunos bytes utilizando mi expansión RegExp.
TheConstructor
6

Java 8, 742 bytes

Podría reducir otros 3 bytes nombrando la función en slugar de sortotros 16 bytes si no cuenta la definición de clase.

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");}}

Se puede usar así:

new H().sort(list);

Banco de pruebas:

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;
}

flexible

[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

Sin golf:

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");
    }
}

Estoy usando el Listtipo de Java y su order()función, pero el comparador es todo mío.

El constructor
fuente
¡Impresionante! Me imagino que debería poder soltar el especificador de tipo de lista <String>y guardar algunos caracteres a costa de algunas advertencias.
Josh
@ Josh nah, produciría dos lanzamientos como Java inferiría Objectcomo tipo de ayb entonces. Sin embargo, probablemente podría escapar definiendo un parámetro genérico de clase que se extienda String. Además, no espero tener el código más corto. ;-)
TheConstructor
3

Pitón 3, 70

Guardado 8 bytes gracias a shooqie.

Amo a Python :RE

Espera una lista de cadenas.

from locale import*;setlocale(0,'hu')
f=lambda x:sorted(x,key=strxfrm)
Morgan Thrapp
fuente
3
¿No es esta una escapatoria estándar?
vsz
1
@vsz No que yo sepa. El uso de elementos integrados es parte de muchos desafíos.
Morgan Thrapp
1
@vsz Tiene una proporción de votos de arriba a abajo demasiado baja en la publicación de vacíos legales estándar para ser contada como estándar, tendrías que prohibirla explícitamente.
FryAmTheEggman
1
Ok, listo Pensé en prohibirlo explícitamente, pero creo que debería ser obvio que convertiría todo el desafío en un punto discutible. Lo siento por las molestias.
vsz
1
from locale import*ahorra muchos bytes
shooqie