Questa è una conseguenza di quei personaggi che hanno lo stesso ordinamento.
Lo noterai anche tu
sort -u << EOF
■
⅕
⅖
⅗
EOF
restituisce solo una riga.
O quello:
expr ■ = ⅕
restituisce true (come richiesto da POSIX).
La maggior parte delle versioni locali fornite con i sistemi GNU hanno un numero di caratteri (e persino sequenze di caratteri (sequenze di confronto)) che hanno lo stesso ordinamento. Nel caso di quei ■ ⅕⅖⅗, è perché l'ordine non è definito e quei caratteri il cui ordine non è definito finiscono per avere lo stesso ordinamento nei sistemi GNU. Ci sono personaggi che sono esplicitamente definiti come aventi lo stesso ordinamento come Ș e Ş (sebbene non ci sia una logica reale apparente (per me comunque) o coerenza su come viene fatto).
Questa è la fonte di comportamenti abbastanza sorprendenti e fasulli. Di recente ho sollevato il problema sulla mailing list del gruppo Austin (l'ente dietro POSIX e le specifiche UNIX) e la discussione è ancora in corso dal 03-04-2015.
In questo caso, non è chiaro se [y]
corrispondere a x
dove x
e y
ordinare lo stesso, ma poiché un'espressione di parentesi deve corrispondere a un elemento di confronto, ciò suggerisce che ilbash
comportamento è previsto.
In ogni caso, suppongo [⅕-⅕]
o almeno [⅕-⅖]
dovrebbe corrispondere■
.
Noterai che strumenti diversi si comportano diversamente. ksh93 si comporta come bash
, GNU grep
o sed
no. Alcune altre shell hanno comportamenti diversi, alcuni comeyash
ancora più buggy.
Per avere un comportamento coerente, è necessario un locale in cui tutti i personaggi si ordinano in modo diverso. La locale C è quella tipica. Tuttavia, il set di caratteri nella locale C sulla maggior parte dei sistemi è ASCII. Sui sistemi GNU, generalmente si ha accesso aC.UTF-8
internazionale che può essere utilizzata invece per lavorare sul carattere UTF-8.
Così:
(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])
o l'equivalente standard:
(export LC_ALL=C.UTF-8
case ■ in ([⅕⅖⅗]) true;; (*) false; esac)
dovrebbe restituire false.
Un'altra alternativa sarebbe quella di impostare solo LC_COLLATE
su C che funzionerebbe su sistemi GNU, ma non necessariamente su altri in cui potrebbe non riuscire a specificare l'ordinamento del carattere multi-byte.
Una lezione di ciò è che l' uguaglianza non è una nozione così chiara come ci si aspetterebbe quando si tratta di confrontare le stringhe. Uguaglianza potrebbe significare, dal più rigoroso al meno rigoroso.
- Lo stesso numero di byte e tutti i componenti byte hanno lo stesso valore.
- Lo stesso numero di caratteri e tutti i caratteri sono uguali (ad esempio, fare riferimento allo stesso punto di codice nel set di caratteri corrente).
- Le due stringhe hanno lo stesso ordinamento secondo l'algoritmo di confronto delle impostazioni locali (ovvero, a <b né b> a non è vero).
Ora, per 2 o 3, ciò presuppone che entrambe le stringhe contengano caratteri validi. In UTF-8 e alcune altre codifiche, alcune sequenze di byte non formano caratteri validi.
1 e 2 non sono necessariamente equivalenti a causa di ciò o perché alcuni caratteri possono avere più di una possibile codifica. Questo è in genere il caso di codifiche stateful come ISO-2022-JP dove A
possono essere espresse come 41
o 1b 28 42 41
(1b 28 42
essendo la sequenza per passare a ASCII e puoi inserire tutte quelle che vuoi, che non faranno la differenza), sebbene io non si aspetterebbe che quei tipi di codifica siano ancora in uso e, almeno in genere, gli strumenti GNU non funzionano correttamente con essi.
Attenzione, inoltre, che la maggior parte delle utility non GNU non è in grado di gestire il valore 0 byte (il carattere NUL in ASCII).
Quale di queste definizioni viene utilizzata dipende dall'utilità e dall'implementazione o dalla versione dell'utilità. POSIX non è chiaro al 100% su questo. Nella locale C, tutti e 3 sono equivalenti. Al di fuori di quel YMMV.