Pourquoi le tri dit-il que ɛ = e?


25

ɛ("Latin epsilon") est une lettre utilisée dans certaines langues africaines, généralement pour représenter le son de voyelle en anglais "bed". En Unicode, il est codé en U + 025B, très différent du quotidien e.

Cependant, si je fais sortce qui suit:

eb
ed
ɛa
ɛc

il semble que sortconsidère ɛet eéquivalent:

ɛa
eb
ɛc
ed

Que se passe t-il ici? Et existe-t-il un moyen de faire ɛet de edistinguer à des sortfins d'ingénierie?


21
les règles de tri sont appelées «collation», si cela aide votre recherche
BlueRaja - Danny Pflughoeft

1
Essayez de mettre un certain nombre de eamélangés à l' ɛaintérieur d'un fichier texte et de le trier. Vous verrez qu'il trie toujours eaavant ɛa. Donc, non, ils ne sont pas considérés comme égaux.
Bakuriu

Cela peut être un point évident, mais je ne l'ai pas encore vu explicitement suggéré: si vous triez des mots dans $ (certain_african_language), la chose naturelle à faire est de définir les paramètres régionaux sur $ (certain_african_language).
Federico Poloni

@FedericoPoloni Un très bon point! Malheureusement, je n'ai pas pu trouver de paramètres régionaux pour cette langue.
Draconis du

1
@ GermánBouzas Il s'agit spécifiquement de "latin epsilon", une forme conçue pour s'adapter à l'alphabet latin. Ils se ressemblent à peu près, mais le epsilon latin est U + 025B, tandis que le epsilon grec est U + 03B5.
Draconis

Réponses:


67

Non, il ne les considère pas comme équivalents, ils ont juste le même poids primaire. De sorte que, en première approximation, ils trient la même chose.

Si vous regardez / usr / share / i18n / locales / iso14651_t1_common (utilisé comme base pour la plupart des locales) sur un système GNU (ici avec la glibc 2.27), vous verrez:

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

e, ɛet Eont le même poids primaire eet le Emême poids secondaire, seul le troisième poids les différencie.

Lors de la comparaison de chaînes, sort(la strcoll()fonction libc standard est utilisée pour comparer les chaînes) commence par comparer les poids principaux de tous les caractères, et ne choisissez le deuxième poids que si les chaînes sont égales aux poids primaires (et ainsi de suite avec les autres poids) .

C'est ainsi que la casse semble être ignorée dans l'ordre de tri en première approximation. Abtrie entre aaet ac, mais Abpeut trier avant ou après abselon la règle de langue (certaines langues ont <MIN>avant <CAP>comme en anglais britannique, d'autres <CAP>avant <MIN>comme en estonien).

Si eavait le même ordre de tri que ɛ, printf '%s\n' e ɛ | sort -une retournerait qu'une seule ligne. Mais comme <BAS>avant <PCL>, eseul avant ɛ . eɛetrie après EEE(au poids secondaire) même si EEEtrie après eee(pour lequel il faut remonter au troisième poids).

Maintenant, si sur mon système avec la glibc 2.27, je lance:

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

Vous remarquerez qu'il y a pas mal de caractères qui ont été définis avec exactement les mêmes 4 poids. En particulier, notre ɛ a les mêmes poids que:

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

Et bien sûr:

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

Cela peut être vu comme un bogue des locales libc GNU. Sur la plupart des autres systèmes, les paramètres régionaux s'assurent que tous les différents caractères ont à la fin un ordre de tri différent. Sur GNU lieux, il devient encore pire, car il y a des milliers de caractères qui ne disposent pas d' un ordre de tri et finissent par le tri même, ce qui provoque toutes sortes de problèmes (comme la rupture comm, join, lsou ayant globs commandes non déterministes ... ), d'où la recommandation d' utiliser LC_ALL=Cpour contourner ces problèmes .

Comme indiqué par @ninjalj dans les commentaires, la glibc 2.28 publiée en août 2018 a apporté quelques améliorations sur ce front, même si AFAICS, il existe encore des caractères ou des éléments de classement définis avec un ordre de tri identique. Sur Ubuntu 18.10 avec glibc 2.28 et dans un environnement local en_GB.UTF-8.

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

(pourquoi U + 00B7 serait-il considéré comme équivalent à U + 0387 uniquement lorsqu'il est combiné avec L/ l?!).

Et:

$ 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

(toujours plus d'un million de caractères (95% de la plage Unicode, contre 98% en 2,27) triant les mêmes caractères que les autres car leur ordre de tri n'est pas défini).

Voir également:


3
Ceci est exactement ce que je cherchais! Pour être complet, que signifie-t-il <PCL>? Les autres semblent être Capital, Miniscule et Basic?
Draconis

3
@Draconis, collation-symbol <PCL> # 16 particulier / peculiar
Stéphane Chazelas

En effet, si nous mettons un tas de eaet ɛamélangés ensemble dans un fichier, nous voyons que sorttout trie eas avant ɛas.
Bakuriu

2
À partir de la glibc 2.28, le point de code doit être utilisé comme solution de rechange
ninjalj

1
@cat, désolé, je voulais dire strcoll(), voir modifier.
Stéphane Chazelas

15

genre homme:

   ***  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.

Alors, essayez: LC_ALL=C sort file.txt


1
Ça marche! Mais pourquoi les paramètres régionaux par défaut considèrent-ils ces points de code complètement séparés comme étant les mêmes? Je suis curieux de savoir pourquoi cela se produit.
Draconis

@Draconis Qu'est-ce que "les paramètres régionaux par défaut"?
Kamil Maciorowski

@KamilMaciorowski Une valeur vide de la variable d'environnement; Je ne sais pas à quel endroit cela correspond.
Draconis

3
@Draconis LC_ALLest vide, sortpeut utiliser d'autres LC_*variables LANGou certains fichiers de configuration.
NieDzejkob

1
LC_COLLATEest la chaîne spécifique au tri, LANGest extra-générale.
ShadowRanger

8

Le caractère ɛ n'est pas égal à e, mais certains paramètres régionaux peuvent regrouper ces signes lors de la collation. La raison en est spécifique à la langue, mais aussi à un contexte historique ou même politique. Par exemple, la plupart des gens s'attendent probablement à ce que la devise € uro se rapproche de l' Europe dans le dictionnaire.

Quoi qu'il en soit, pour voir le classement que vous utilisez actuellement locale, run locale -avous donnera la liste des paramètres régionaux disponibles sur le système et pour changer le classement, disons Cjuste pour un seul tri LC_COLLATE=C sort file. Enfin, pour voir comment différents paramètres régionaux peuvent trier votre fichier, essayez

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

Dirigez le résultat vers un outil de greping pour choisir les paramètres régionaux qui correspondent à vos besoins.


C'est une merveilleuse explication, mais les symboles semblent être considérés comme identiques, pas seulement rapprochés.
Draconis

1
Non, ils ne sont pas considérés comme identiques. Ajoutez une ealigne simple au fichier, puis sort -uvous obtiendrez à la fois eaet ɛadans la sortie. La meilleure stratégie contre l'assemblage est d' éviter ( export LC_COLLATE=C). Sinon, beaucoup de choses laides qui va se passer (par exemple. /tmp/[a-z]En bashcorrespondront /tmp/aet /tmp/Anon /tmp/Z).
mosvy

@mosvy Huh, intéressant… donc ils sont considérés comme les mêmes à des fins de commande mais pas à des fins d'unicité?
Draconis

ils ne sont pas considérés comme les mêmes. voir ici une explication à ce sujet.
mosvy

1
@ninjalj, qui peut être corrigé dans les fnmatch()plages glibc et regexp, mais pas dans certains comme bashcelui qui implémente ses plages en utilisant lui-même strcoll(). ksh93 n'a jamais eu le problème car son implémentation de plage utilise strcoll()et vérifie également la casse des fins de plage et ne fait correspondre les caractères en minuscules que si les deux extrémités sont en minuscules. Les plages zsh n'ont pas le problème car elles sont basées sur le point de code, pas sur strcoll ().
Stéphane Chazelas
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.