При включенных локалях сопоставление выполняется за несколько проходов. Каждый персонаж имеет четыре веса, которые сравниваются в последовательных проходах. Знаки @
и _
, как и большинство знаков препинания, не имеют первичного, вторичного или третичного веса, поэтому они вступают в игру только на четвертом проходе. Итак, для вашего примера
aaa2000@yahoo.com > aaa_2000@yahoo.com
в первом проходе, это действительно сравнение
aaa2000yahoocom = aaa2000yahoocom
, а затем на четвертом проходе (во втором и третьем проходах нет дифференцирующих факторов)
@. > _@.
потому что @
оказывается больше, чем _
в этой локали. (Это просто выбор, который делает определение локали, предположительно на основе какого-либо стандарта ISO или другого.)
Вы можете заглянуть в детали реализации этого. Сравнение с поддержкой локали в конечном итоге будет реализовано в библиотеке C как strxfrm(A) cmp strxfrm(B)
. Запустите эту программу:
use POSIX;
my $s1 = 'aaa2000@yahoo.com';
my $s2 = 'aaa_2000@yahoo.com';
foreach ($s1, $s2) {
printf "%s =>\t%v02x\n", $_, POSIX::strxfrm($_);
}
Я получаю:
aaa2000@yahoo.com => 0c.0c.0c.04.02.02.02.24.0c.13.1a.1a.0e.1a.18.01.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.01.02.02.02.02.02.02.02.02.02.02.02.02.02.02.02.01.08.5d.06.44
# explanation: a a a 2 0 0 0 y a h o o c o m DIV secondary weights ... DIV tertiary weights ... DIV @ .
aaa_2000@yahoo.com => 0c.0c.0c.04.02.02.02.24.0c.13.1a.1a.0e.1a.18.01.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.01.02.02.02.02.02.02.02.02.02.02.02.02.02.02.02.01.04.36.05.5d.06.44
# explanation: a a a 2 0 0 0 y a h o o c o m DIV secondary weights ... DIV tertiary weights ... DIV _ @ .
Способ получения этих чисел - деталь реализации; они просто должны выйти так, чтобы сравнение байтов дало желаемый конечный результат. Но концепция одинакова во всех современных средах программирования с сортировкой с поддержкой локали.