Dlaczego sort mówi, że ɛ = e?


25

ɛ(„Latin epsilon”) to litera używana w niektórych językach afrykańskich, zwykle reprezentująca dźwięk samogłoski w angielskim „łóżku”. W Unicode jest zakodowany jako U + 025B, co różni się od codzienności e.

Jeśli jednak sort:

eb
ed
ɛa
ɛc

wydaje się, że sortuważa ɛi erównoważne:

ɛa
eb
ɛc
ed

Co tu się dzieje? A czy jest jakiś sposób, aby ɛi eodrębne dla sortcelów ing?


21
Reguły sortowania są nazywane 'zestawień', jeśli to pomaga googling
BlueRaja - Danny Pflughoeft

1
Spróbuj umieścić pewną liczbę eazmieszanych z ɛawewnątrz pliku tekstowego i posortuj go. Przekonasz się, że zawsze to sortuje eawcześniej ɛa. Więc nie, nie są one uważane za równe.
Bakuriu

Może to być oczywisty punkt, ale nie widziałem tego wyraźnie sugerowanego: jeśli sortujesz słowa w $ (pewien_język_frykański), naturalną rzeczą do zrobienia jest ustawienie ustawień regionalnych na $ (pewien_język_afrykański).
Federico Poloni

@FedericoPoloni Bardzo dobry punkt! Niestety nie udało mi się znaleźć ustawień regionalnych dla tego języka.
Draconis,

1
@ GermánBouzas Jest to specjalnie „łaciński epsilon”, forma zaprojektowana z myślą o alfabecie łacińskim. Wyglądają prawie tak samo, ale łaciński epsilon to U + 025B, podczas gdy grecki epsilon to U + 03B5.
Draconis,

Odpowiedzi:


67

Nie, nie uważa się ich za równoważne, po prostu mają tę samą pierwotną wagę. Tak więc, w pierwszym przybliżeniu, sortują to samo.

Jeśli spojrzysz na / usr / share / i18n / locales / iso14651_t1_common (jako podstawę większości ustawień narodowych) w systemie GNU (tutaj z glibc 2.27), zobaczysz:

<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U025B> <e>;<PCL>;<MIN>;IGNORE # 287 ɛ
<U0045> <e>;<BAS>;<CAP>;IGNORE # 577 E

e, ɛI Ema taki sam ciężar podstawowy, ei Etaki sam ciężar wtórnego tylko trzecia masa odróżnia je.

Podczas porównywania ciągów sort( strcoll()standardowa funkcja libc służy do porównywania ciągów) zaczyna się od porównania głównych wag wszystkich znaków i przechodzi na drugą wagę tylko wtedy, gdy ciągi są równe pierwotnym wagom (i tak dalej z innymi wagami) .

W ten sposób wielkość liter wydaje się być ignorowana w kolejności sortowania w pierwszym przybliżeniu. Absortuje pomiędzy aai ac, ale Abmoże sortować przed lub po, w abzależności od reguły językowej (niektóre języki miały <MIN>wcześniej <CAP>jak w brytyjskim angielskim, niektóre <CAP>wcześniej <MIN>jak w estońskim).

Gdyby emiał taką samą kolejność sortowania jak ɛ, printf '%s\n' e ɛ | sort -uzwróciłby tylko jedną linię. Ale jak <BAS>poprzednio <PCL>, esam sortuje wcześniej ɛ . eɛesortuje po EEE(według wagi wtórnej), chociaż EEEsortuje po eee(dla której musimy przejść do trzeciej wagi).

Teraz, jeśli w moim systemie z glibc 2.27, uruchamiam:

sed -n 's/\(.*;[^[:blank:]]*\).*/\1/p' /usr/share/i18n/locales/iso14651_t1_common |
  sort -k2 | uniq -Df1

Zauważysz, że istnieje wiele znaków, które zostały zdefiniowane z dokładnie tymi samymi 4 wagami. W szczególności nasze ɛ ma takie same wagi jak:

<U01DD> <e>;<PCL>;<MIN>;IGNORE
<U0259> <e>;<PCL>;<MIN>;IGNORE
<U025B> <e>;<PCL>;<MIN>;IGNORE

I na pewno:

$ printf '%s\n' $'\u01DD' $'\u0259' $'\u025B' | sort -u
ǝ
$ expr ɛ = ǝ
1

Można to uznać za błąd w ustawieniach narodowych GNU libc. W większości innych systemów ustawienia narodowe zapewniają, że wszystkie znaki mają na końcu inną kolejność sortowania. Na lokalizacjach GNU, robi się jeszcze gorzej, ponieważ istnieją tysiące znaków, które nie mają sortowania i skończyć sortowania samo, powodując różnego rodzaju problemy (jak łamanie comm, join, lslub globs mających niedeterministycznym zleceń ... ), stąd zalecenie używania w LC_ALL=Ccelu obejścia tych problemów .

Jak zauważył @ninjalj w komentarzach, glibc 2.28 wydany w sierpniu 2018 roku przyszedł z pewnymi ulepszeniami na tym froncie, chociaż AFAICS, nadal istnieje kilka znaków lub elementów zestawiających zdefiniowanych w identycznej kolejności sortowania. Na Ubuntu 18.10 z glibc 2.28 oraz w ustawieniach regionalnych en_GB.UTF-8.

$ expr $'L\ub7' = $'L\u387'
1

(dlaczego U + 00B7 miałby być uważany za równoważny jako U + 0387 tylko w połączeniu z L/ l?!).

I:

$ perl -lC -e 'for($i=0; $i<0x110000; $i++) {$i = 0xe000 if $i == 0xd800; print chr($i)}' | sort > all-chars-sorted
$ uniq -d all-chars-sorted | wc -l
4
$ uniq -D all-chars-sorted | wc -l
1061355

(wciąż ponad 1 milion znaków (95% zakresu Unicode, w porównaniu z 98% w 2.27) sortuje się tak samo jak inne znaki, ponieważ ich kolejność sortowania nie jest zdefiniowana).

Zobacz też:


3
Właśnie tego szukałem! Dla kompletności, co oznacza <PCL>? Pozostałe wydają się być kapitałowe, małe i podstawowe?
Draconis

3
@Draconis, symbol
Stéphane Chazelas

Rzeczywiście, jeśli umieścimy kilka eai ɛazmiksujemy razem w pliku, zobaczymy, że sortsortuje wszystkie eas przed ɛas.
Bakuriu

2
Od wersji glibc 2.28 punkt kodowy powinien być używany jako rezerwowy dla wagi 4. poziomu, patrz sourceware.org/git/… sourceware.org/bugzilla/show_bug.cgi?id=14095
ninjalj

1
@cat, przepraszam, miałem na myśli strcoll(), zobacz edycję.
Stéphane Chazelas

15

rodzaj człowieka:

   ***  WARNING  ***  The locale specified by the environment affects sort
   order.  Set LC_ALL=C to get the traditional sort order that uses native
   byte values.

Więc spróbuj: LC_ALL=C sort file.txt


1
To działa! Ale dlaczego domyślne ustawienia narodowe uważają te całkowicie oddzielne punkty kodowe za takie same? Jestem ciekawy, dlaczego tak się dzieje.
Draconis

@Draconis Co to są „domyślne ustawienia regionalne”?
Kamil Maciorowski

@KamilMaciorowski Pusta wartość zmiennej środowiskowej; Nie jestem pewien, jakie ustawienia regionalne to odpowiada.
Draconis

3
@Draconis, jeśli LC_ALLjest pusty, sortmoże używać innych LC_*zmiennych LANGlub niektórych plików konfiguracyjnych.
NieDzejkob

1
LC_COLLATEjest specyficzny dla łańcucha znaków, LANGjest bardziej ogólny.
ShadowRanger

8

Znak ɛ nie jest równy e, ale niektóre lokalizacje mogą zbierać te znaki blisko siebie po zestawieniu. Powodem tego jest specyficzne dla języka, ale także pewne tło historyczne, a nawet polityczne. Na przykład większość osób prawdopodobnie oczekuje, że w walucie euro uro zbliża się do Europy .

W każdym razie, aby zobaczyć, jakiego sortowania używasz obecnie locale, locale -awyświetli się lista ustawień regionalnych dostępnych w systemie i zmień sortowanie, powiedz, że Ctylko dla jednego sortowania LC_COLLATE=C sort file. Na koniec, aby zobaczyć, jak różne ustawienia regionalne mogą posortować plik, spróbuj

for loc in $(locale -a)
    do echo ____"${loc}"____
    LC_COLLATE="$loc" sort file
done

Prześlij wynik do jakiegoś narzędzia greping, aby wybrać ustawienia regionalne odpowiadające twoim potrzebom.


To wspaniałe wyjaśnienie, ale symbole wydają się być uważane za identyczne, a nie tylko blisko siebie.
Draconis,

1
Nie, nie są uważane za identyczne. Dodaj zwykłą ealinię do pliku, a następnie sort -udostaniesz oba eai ɛana wyjściu. Najlepszą strategią kontra zestawieniem jest unikanie ( export LC_COLLATE=C). W przeciwnym razie, wiele brzydkich rzeczy się wydarzy (np. /tmp/[a-z]W bashdopasuje /tmp/aa /tmp/Ajednak nie /tmp/Z).
mosvy

@mosvy Huh, ciekawe… więc są uważane za takie same do celów zamawiania, ale nie do celów wyjątkowości?
Draconis

nie są uważane za takie same. zobacz tutaj wyjaśnienie na ten temat.
mosvy

1
@ ninjalj, które można naprawić w fnmatch()zakresach glibc i regexp, ale nie w niektórych podobnych bashimplementować zakresy samodzielnie strcoll(). ksh93 nigdy nie miał problemu, ponieważ jego implementacja zakresu używa, strcoll()a także sprawdza wielkość liter końca zakresu i dopasowuje tylko małe litery, jeśli oba końce są małymi literami. W zakresach zsh nie ma problemu, ponieważ odbywa się to na podstawie kodu, a nie strcoll ().
Stéphane Chazelas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.