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 E
ont le même poids primaire e
et le E
mê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. Ab
trie entre aa
et ac
, mais Ab
peut trier avant ou après ab
selon la règle de langue (certaines langues ont <MIN>
avant <CAP>
comme en anglais britannique, d'autres <CAP>
avant <MIN>
comme en estonien).
Si e
avait le même ordre de tri que ɛ
, printf '%s\n' e ɛ | sort -u
ne retournerait qu'une seule ligne. Mais comme <BAS>
avant <PCL>
, e
seul avant ɛ
. eɛe
trie après EEE
(au poids secondaire) même si EEE
trie 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
, ls
ou ayant globs commandes non déterministes ... ), d'où la recommandation d' utiliser LC_ALL=C
pour 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: