Não, não os considera equivalentes, apenas têm o mesmo peso principal. Para que, na primeira aproximação, eles tenham a mesma classificação.
Se você olhar para / usr / share / i18n / locales / iso14651_t1_common (usado como base para a maioria das localidades) em um sistema GNU (aqui com 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
tem o mesmo peso primário, e
e E
mesmo peso secundário, apenas o terceiro peso diferencia-os.
Ao comparar strings, sort
(a strcoll()
função libc padrão é usada para comparar strings) começa comparando os pesos primários de todos os caracteres e só vai para o segundo peso se os 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
sortes entre aa
e ac
, mas Ab
pode classificar antes ou depois ab
, dependendo da regra de linguagem (algumas línguas têm <MIN>
antes <CAP>
como em Inglês Britânico, alguns <CAP>
antes <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>
antes <PCL>
, e
só antes ɛ
. eɛe
classifica depois EEE
(no peso secundário), mesmo que EEE
classifique depois eee
(para o qual precisamos subir até o terceiro peso).
Agora, se no meu sistema com glibc 2.27, eu corro:
sed -n 's/\(.*;[^[:blank:]]*\).*/\1/p' /usr/share/i18n/locales/iso14651_t1_common |
sort -k2 | uniq -Df1
Você notará que existem alguns caracteres que foram definidos com exatamente 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 dos locais de GNU libc. Na maioria dos outros sistemas, as localidades garantem que todos os caracteres diferentes tenham ordem de classificação diferente no final. Em localidades GNU, fica ainda pior, pois há milhares de caracteres que não têm uma ordem de classificação e acabam classificando o mesmo, causando todo tipo de problemas (como quebrar comm
, join
, ls
ou globs tendo ordens não-deterministas ... ), daí a recomendação de usar LC_ALL=C
para solucionar esses problemas .
Como observado por @ninjalj nos comentários, o glibc 2.28 lançado em agosto de 2018 veio com algumas melhorias nessa frente do AFAICS, ainda existem alguns caracteres ou elementos de classificação definidos com ordem de classificação idêntica. No Ubuntu 18.10 com glibc 2.28 e em um local en_GB.UTF-8.
$ expr $'L\ub7' = $'L\u387'
1
(por que U + 00B7 seria considerado equivalente a 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 da mesma forma que outros caracteres, pois sua ordem de classificação não está definida).
Veja também: