web-dev-qa-db-fra.com

Pourquoi le tri dit-il que ɛ = e?

ɛ ("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 encodé en U + 025B, très différent du e de tous les jours.

Cependant, si je sort ce qui suit:

eb
ed
ɛa
ɛc

il semble que sort considère ɛ et e équivalent:

ɛa
eb
ɛc
ed

Que se passe t-il ici? Et existe-t-il un moyen de faire ɛ et e distincts pour sorting?

26
Draconis

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 E même poids secondaire, seul le troisième poids les différencie.

Lors de la comparaison de chaînes, sort (la fonction libc standard strcoll() est utilisée pour comparer les chaînes) commence par comparer les poids principaux de tous les caractères, et ne choisit le deuxième poids que si les chaînes sont égales. avec les 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, certains <CAP> Avant <MIN> Comme en estonien).

Si e avait le même ordre de tri que ɛ, printf '%s\n' e ɛ | sort -u Renverrait une seule ligne. Mais comme <BAS> Trie avant <PCL>, e seul trie avant ɛ . eɛe Trie après EEE (au poids secondaire) même si EEE trie après eee (pour lequel nous devons aller jusqu'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 de GNU libc locales. Sur la plupart des autres systèmes, les locales s'assurent que tous les différents caractères ont un ordre de tri différent à la fin. On GNU = locales, cela devient encore pire, car il y a des milliers de caractères qui n'ont pas d'ordre de tri et finissent par trier le même, provoquant toutes sortes de problèmes (comme casser comm, join , ls ou globs ayant des ordres non déterministes ...), d'où la recommandation de en utilisant 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:

67
Stéphane Chazelas

homme trie:

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

15
Ipor Sircer

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 devise euro uro se rapproche de Europe dans le dictionnaire.

Quoi qu'il en soit, pour voir le classement que vous utilisez actuellement, exécutez locale, le locale -a vous donnera la liste des paramètres régionaux disponibles sur le système et pour changer le classement, par exemple en C juste pour un cycle de 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.

8
jimmij