Венгерский алфавитный порядок

19

Для тех, кто желает намного больше испытаний, чем старый испанский алфавитный порядок , давайте посмотрим, как упорядочен венгерский алфавит.

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

на самом деле, q, w, xи yне используются в венгерских слов, но они включены в заимствованных и иностранных имен. Иностранные акцентированные символы, которые не являются частью венгерского алфавита (например ñ), имеют тот же приоритет, что и неакцентированные, но мы игнорируем их для этой задачи.

Правила обобщены:

  • Диграфы ( cs, szи т. Д.) И триграф ( dzs) рассматриваются как самостоятельные буквы.
cudar
cukor
cuppant
csalit
csata
  • Если же орграф или триграф происходит дважды непосредственно друг за другом в слове, они написаны в упрощенном виде: sszвместо того szsz, ddzsвместо того , dzsdzsно в алфавитном порядке используется не упростили порядок. Например kasza< kaszinó< kassza, так как kasszaиспользуется как k+ a+ sz+ sz+ aради упорядочения. Иногда вы можете найти несокращенную версию в слове, в случае составных слов.
kasza
kaszinó
kassza
kaszt
nagy
naggyá
nagygyakorlat
naggyal
nagyít
  • использование заглавных букв не имеет значения, за исключением случаев, когда два слова были бы совершенно одинаковыми без использования заглавных букв, и в этом случае строчная буква имеет приоритет
jácint
Jácint
Zoltán
zongora
  • Короткие и длинные версии акцентированных гласными имеют одинаковый приоритет ( a - á, e -é, i - í, o - ó, ö - ő, u - ú ü - ű), с одним исключением: если два слова , иначе было бы точно так же, короткий гласный имеет приоритет над долгими гласными. Обратите внимание, что гласные с умлаутом ( öи ü) - это совершенно разные символы от oи u.
Eger
egér
író
iroda
irónia
kerek
kerék
kérek
szúr
szül
  • Дефисы или пробелы (например, в составных словах, именах и т. Д.) Полностью игнорируются
márvány
márványkő
márvány sírkő
Márvány-tenger
márványtömb

Задание

Ваша программа / функция получает строки, состоящие из символов венгерского алфавита (как в нижнем, так и в верхнем регистре), но строка может содержать пробелы или дефисы. Для простоты знак минус (ASCII 45) можно использовать в качестве дефиса. Обратите внимание, что некоторые символы (такие как ő) не являются частью ASCII. Вы можете использовать любую кодировку, если пожелаете, если она поддерживает все необходимые символы.

Вы должны правильно упорядочить строки и отобразить / вернуть результат.

Вы можете использовать любое произвольно упорядоченное подмножество приведенных выше примеров для тестирования.

РЕДАКТИРОВАТЬ:

Пожалуйста, не используйте какой-либо встроенный или другой способ, который уже знает венгерский алфавитный порядок самостоятельно. Это сделало бы соревнование бессмысленным и взяло бы на себя все трудности, связанные с поиском лучшего регулярного выражения или лучших трюков в коде.

EDIT2:

Чтобы очистить пояснение, заданное isaacg: «две строки, которые отличаются только заглавными буквами и длинными и короткими гласными, но различаются в обоих направлениях»: хотя ни одно из правил в официальном документе явно не решает этот вопрос, пример можно найти в точках длины гласного, имеющего большее значение, чем капитализация.

ВСЗ
источник
@FryAmTheEggman Где ты это видишь?
Морган Трепп
9
Чувак, я даже не могу запомнить наш правильный алфавитный порядок. Как я собираюсь запрограммировать это? ;)
Андрас Дик
1
Я пытался придумать контрпример к обязательному провалу, где очевидный орграф на самом деле состоит из двух букв, таких как malacsültили nyílászáró. Интересно, есть ли они (но вам понадобится словарный запас, чтобы проверить это, что, по-видимому, не является частью этой задачи)
Андрас Дик
1
Нет примера, содержащего dzs
TheConstructor

Ответы:

4

Perl, 250

Включает в себя +11 для -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}<>

Использует идиому decorate-sort-undecorate (AKA Schwartzian Transform ) и многоуровневую сортировку , где уровни:

  • L1: сравнивайте базовые буквы, игнорируйте диакритические знаки, регистр и некоторые знаки препинания.
  • L2: сравнивайте базовые буквы и диакритические знаки, игнорируйте регистр и некоторые знаки препинания.
  • L3: сравнивайте базовые буквы, диакритические знаки и регистр, игнорируйте пунктуацию.
  • Ln: сравнение уровня байтов.

Внутренне (ASCII 0x1C Разделитель полей - значение которого меньше, чем любой символ в алфавите для этой задачи) используется в качестве разделителя уровня.

Эта реализация имеет много ограничений, среди которых:

  • Нет поддержки иностранных символов.
  • Невозможно устранить неоднозначность между сокращенными (длинными) оргразами / триграфами и согласными + орграфом / триграфом, например: könnyű должен сопоставляться как <k> <ö> <ny> <ny> <ű> , а tizennyolc должен сопоставляться как <t> < i> <z> <e> <n> <ny> <o> <l> <c> ; házszám 'адрес = номер дома (ház) (szám)' должен сопоставляться как <h> <á> <z> <sz> <á> <m>, а не как * <h> <á> <zs> <z> <а> <м> .
  • Сортировка для сокращенных длинных орграфов не является такой последовательной (но она стабильна): мы устраняем неоднозначность на идентичном уровне ( ssz < n szsz, ..., zszs < n zzs ); glibc собирает короткие формы перед полными формами ( ssz <szsz, ..., zzs <zszs ), ICU собирает длинные формы перед короткими формами, начинающимися с L3 Case и вариантов ( szsz < 3 ssz, ..., zszs < 3 зз )

Расширенная версия:

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

†. Некоторыми известными многоуровневыми алгоритмами сопоставления являются Unicode Collation Algorithm (UCA, Unicode UTS # 10) , ISO 14651 (доступно на сайте ITTF ISO ), части LC_COLLATE в ISO TR 30112 (черновик доступен в ISO / IEC JTC1 / SC35 / WG5 home ), который устарел ISO / IEC TR 14652 (доступен в ISO / IEC JTC1 / SC22 / WG20 home ) и LC_COLLATE в POSIX.

‡. Чтобы сделать это правильно, потребуется словарь. ICU лечит Weirdly капитализированных групп , как не-сокращения / Non-орграфы / Non-триграфы, например: CCs < 3 CCs < 3 с Cs < 3 с CS < 3 C Cs < 3 сСт < 3 CS < 3 Cs < 3 CS < 3 ccs < 3 Ccs < 3 CCS

ninjalj
источник
Вы должны быть в состоянии сохранить несколько байтов, используя мое расширение RegExp.
TheConstructor
6

Java 8, 742 байта

Может быть уменьшен еще на 3 байта, называя функцию sвместо sortили еще на 16 байтов, если не считать определение класса.

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

Можно использовать так:

new H().sort(list);

Тестирование:

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

получая

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

Я использую Java- Listтип и order()-функцию, но компаратор - мой.

TheConstructor
источник
Впечатляет! Я полагаю, что вы сможете удалить спецификатор типа списка <String>и сохранить несколько символов за счет нескольких предупреждений?
Джош
@ Джош, нет, это произвело бы два приведения, тогда как Java выглядела бы Objectкак a и b. Я, вероятно, мог бы уйти от определения расширения общего параметра класса String. Также я не ожидаю иметь самый короткий код. ;-)
TheConstructor
3

Python 3, 70

Сохранено 8 байтов благодаря shooqie.

Я люблю Python. : D

Ожидается список строк.

from locale import*;setlocale(0,'hu')
f=lambda x:sorted(x,key=strxfrm)
Морган Трепп
источник
3
Разве это не стандартная лазейка?
вс
1
@vsz Не так, как я знаю. Использование встроенных модулей является частью множества проблем.
Морган Трепп
1
@vsz Слишком низкое соотношение голосов к стандартным сообщениям о лазейках, чтобы считаться стандартом, вы должны явно запретить.
FryAmTheEggman
1
Хорошо, сделали это. Я подумал о том, чтобы явно запретить его, но я думаю, должно быть очевидно, что это сделает весь вопрос спорным. Извините за неудобства.
вс
1
from locale import*экономит много байтов
shooqie