Não, não os considera equivalentes, eles apenas têm o mesmo peso primário. Então, na primeira aproximação, eles ordenam o mesmo.
Se você olhar para / usr / share / i18n / locales / iso14651_t1_common (como é usado como base para a maioria das localidades) em um sistema GNU (aqui com o glibc 2.27), você verá:
<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U025B> <e>;<PCL>;<MIN>;IGNORE # 287 ɛ
<U0045> <e>;<BAS>;<CAP>;IGNORE # 577 E
e
, ɛ
e E
têm o mesmo peso primário, e
e E
mesmo peso secundário, apenas o terceiro peso os diferencia.
Ao comparar strings, sort
(a função strcoll()
padrão libc é usada para comparar strings) começa comparando os pesos primários de todos os caracteres, e só vai para o segundo peso se as strings forem iguais aos pesos primários (e assim por diante com os outros pesos).
É assim que o caso parece ser ignorado na ordem de classificação na primeira aproximação. Ab
classifica entre aa
e ac
, mas Ab
pode classificar antes ou depois de ab
dependendo da regra de idioma (alguns idiomas têm <MIN>
antes <CAP>
como em inglês britânico, alguns <CAP>
antes de <MIN>
como em estoniano).
Se e
tivesse a mesma ordem de classificação que ɛ
, printf '%s\n' e ɛ | sort -u
retornaria apenas uma linha. Mas como <BAS>
classifica antes de <PCL>
, e
classifica antes ɛ
. eɛe
classifica após EEE
(no peso secundário) mesmo que EEE
ordene após eee
(para o qual precisamos subir para o terceiro peso).
Agora, se no meu sistema com o glibc 2.27, eu corro:
sed -n 's/\(.*;[^[:blank:]]*\).*//p' /usr/share/i18n/locales/iso14651_t1_common |
sort -k2 | uniq -Df1
Você notará que existem alguns caracteres que foram definidos exatamente com os mesmos 4 pesos. Em particular, nosso ɛ tem os mesmos pesos que:
<U01DD> <e>;<PCL>;<MIN>;IGNORE
<U0259> <e>;<PCL>;<MIN>;IGNORE
<U025B> <e>;<PCL>;<MIN>;IGNORE
E com certeza:
$ printf '%s\n' $'\u01DD' $'\u0259' $'\u025B' | sort -u
ǝ
$ expr ɛ = ǝ
1
Isso pode ser visto como um bug das localidades GNU libc. Na maioria dos outros sistemas, as localidades garantem que todos os diferentes caracteres tenham uma ordem de classificação diferente no final. Nas localidades GNU, fica ainda pior, pois existem milhares de caracteres que não têm uma ordem de classificação e acabam classificando os mesmos, causando todos os tipos de problemas (como comm
, join
, ls
ou% globs tendo ordens não-determinísticas ...), daí a recomendação de usando LC_ALL=C
para contornar essas questões .
Como foi observado por @ninjalj nos comentários, o glibc 2.28 lançado em agosto de 2018 veio com algumas melhorias nessa frente, apesar do AFAICS, ainda existem alguns caracteres ou elementos de agrupamento definidos com ordem de classificação idêntica. No Ubuntu 18.10 com glibc 2.28 e em uma localidade en_GB.UTF-8.
$ expr $'L\ub7' = $'L\u387'
1
(por que U + 00B7 seria considerado equivalente como U + 0387 somente quando combinado com L
/ l
?!).
E:
$ 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
(ainda mais de 1 milhão de caracteres (95% do intervalo Unicode, abaixo de 98% em 2,27) classificando o mesmo que outros caracteres, pois sua ordem de classificação não está definida).
Veja também: