Сравнение строк
Как мы знаем из главы Операторы сравнения, строки сравниваются посимвольно в алфавитном порядке.
Тем не менее, есть некоторые нюансы.
- Строчные буквы больше заглавных:
alert( 'a' > 'Z' ); // true
- Буквы, имеющие диакритические знаки, идут «не по порядку»:
alert( 'Österreich' > 'Zealand' ); // true
Это может привести к своеобразным результатам при сортировке названий стран: нормально было бы ожидать, чтоZealand
будет послеÖsterreich
в списке.
Чтобы разобраться, что происходит, давайте ознакомимся с внутренним представлением строк в JavaScript.
Строки кодируются в UTF-16. Таким образом, у любого символа есть соответствующий код. Есть специальные методы, позволяющие получить символ по его коду и наоборот.str.codePointAt(pos)
Возвращает код для символа, находящегося на позиции pos
:
// одна и та же буква в нижнем и верхнем регистре
// будет иметь разные коды
alert( "z".codePointAt(0) ); // 122
alert( "Z".codePointAt(0) ); // 90
String.fromCodePoint(code)
Создаёт символ по его коду code
alert( String.fromCodePoint(90) ); // Z
Также можно добавлять юникодные символы по их кодам, используя \u
с шестнадцатеричным кодом символа:
// 90 — 5a в шестнадцатеричной системе счисления
alert( '\u005a' ); // Z
Давайте сделаем строку, содержащую символы с кодами от 65
до 220
— это латиница и ещё некоторые распространённые символы:
let str = '';
for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i);
}
alert( str );
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
Как видите, сначала идут заглавные буквы, затем несколько спецсимволов, затем строчные и Ö
ближе к концу вывода.
Теперь очевидно, почему a > Z
.
Символы сравниваются по их кодам. Больший код — больший символ. Код a
(97) больше кода Z
(90).
- Все строчные буквы идут после заглавных, так как их коды больше.
- Некоторые буквы, такие как
Ö
, вообще находятся вне основного алфавита. У этой буквы код больше, чем у любой буквы отa
доz
.
Правильное сравнение
«Правильный» алгоритм сравнения строк сложнее, чем может показаться, так как разные языки используют разные алфавиты.
Поэтому браузеру нужно знать, какой язык использовать для сравнения.
К счастью, все современные браузеры (для IE10− нужна дополнительная библиотека Intl.JS) поддерживают стандарт ECMA 402, обеспечивающий правильное сравнение строк на разных языках с учётом их правил.
Для этого есть соответствующий метод.
Вызов str.localeCompare(str2) возвращает число, которое показывает, какая строка больше в соответствии с правилами языка:
- Отрицательное число, если
str
меньшеstr2
. - Положительное число, если
str
большеstr2
. 0
, если строки равны.
Например:
alert( 'Österreich'.localeCompare('Zealand') ); // -1
У этого метода есть два дополнительных аргумента, которые указаны в документации. Первый позволяет указать язык (по умолчанию берётся из окружения) — от него зависит порядок букв. Второй — определить дополнительные правила, такие как чувствительность к регистру, а также следует ли учитывать различия между "a"
и "á"
.