Привет, меня зовут Дмитрий, я React-разработчик, и сегодня хочу рассказать о методе localeCompare в JavaScript. Мне кажется, что этот метод не так часто используется при сортировке строк, хотя он действительно заслуживает внимания. Многие привыкли к стандартным методам сравнения, но localeCompare позволяет учесть важные нюансы, такие как языковые особенности, регистр символов и числовую сортировку. Я постараюсь раскрыть все его возможности и показать, как можно использовать его для улучшения сортировки данных в проектах.
Введение
При работе со строками в JavaScript часто возникает необходимость их сравнивать и сортировать. Например, это требуется при отображении списка имен пользователей, упорядочивании товаров в интернет-магазине или обработке текстовых данных. На первый взгляд, задача может показаться простой — достаточно использовать операторы сравнения (>, <, ===). Однако такой подход имеет ряд недостатков, особенно если учитывать языковые особенности, регистр букв и специальные символы.
Проблемы стандартного сравнения строк
В JavaScript строки сравниваются посимвольно на основе их кодов Unicode. Это может приводить к неожиданным результатам:
console.log("apple" > "banana"); // false (ожидаемо)
console.log("Zebra" > "apple"); // false (ожидали true, но код 'Z' < 'a')
console.log("straße" === "Strasse"); // false (в немецком языке они считаются одинаковыми)
Основные проблемы:
Регистрозависимость. Например, «Zebra» > «apple» возвращает false, так как заглавная Z имеет меньший Unicode‑код, чем строчная a.
Проблемы с диакритическими знаками. «straße» !== «Strasse», хотя в немецком языке эти слова считаются идентичными.
-
Некорректное сравнение строк с числами. Например:
console.log(["file10", "file2"].sort()); // ["file10", "file2"]
Ожидаемый порядок: ["file2", "file10"], но строки сравниваются посимвольно, и "1" в "file10" идет раньше "2" в "file2".
Зачем нужен localeCompare?
Метод localeCompare позволяет сравнивать строки с учетом языковых особенностей, правил сортировки и дополнительных параметров. Например:
console.log('ёжик'.localeCompare('яблоко', 'ru')); // -1 (Ё считается перед Я)
console.log('ёлка'.localeCompare('ежевика', 'ru', { sensitivity: 'base' })); // -1 (игнорируется разница между Ё и Е)
console.log('файл10'.localeCompare('файл2', 'ru', { numeric: true })); // 1 (правильная числовая сортировка)
console.log('мост'.localeCompare('Москва', 'ru', { sensitivity: 'case' })); // 1 (различается регистр)
В русском языке буква Ё идет перед Я, поэтому «ёжик» раньше «яблоко».
При sensitivity: «base» буквы Е и Ё считаются одинаковыми.
numeric: true позволяет правильно сортировать строки с числами (обычно «файл10» шло бы перед «файл2»).
sensitivity: «case» различает регистр, «Москва» будет раньше «мост».
Этот метод полезен для работы с кириллическими текстами, особенно в случае алфавитных списков и каталогов.
Преимущества localeCompare:
Корректное сравнение строк в разных языках. Учитываются особенности алфавитов и диакритические знаки.
Настраиваемая сортировка. Можно игнорировать регистр, учитывать числовые значения и изменять порядок сортировки.
Поддержка во всех современных браузерах. Это встроенный метод, который не требует дополнительных библиотек.
Основы метода localeCompare
Метод localeCompare используется для сравнения двух строк с учетом языковой локали и дополнительных параметров. В отличие от стандартного посимвольного сравнения, он учитывает особенности алфавита, регистр, числовые значения и национальные правила сортировки.
string1.localeCompare(string2, [locales], [options])
Описание параметров:
string2 - строка, с которой производится сравнение.
locales — (необязательный) — код языка или массив кодов, например «en» (английский), «ru» (русский), «de» (немецкий). Если не указано, используется локаль системы.
options — (необязательный) — объект с настройками, влияющими на поведение сравнения.
Пример без указания локали:
console.log("apple".localeCompare("banana")); // -1 (apple перед banana)
console.log("banana".localeCompare("apple")); // 1 (banana после apple)
console.log("apple".localeCompare("apple")); // 0 (строки равны)
Пример с указанием локали:
console.log("ä".localeCompare("z", "de")); // -1 (в немецком "ä" идет перед "z")
console.log("ä".localeCompare("z", "sv")); // 1 (в шведском "ä" идет после "z")
Использование настроек (options)
Метод localeCompare поддерживает объект options, который позволяет настраивать поведение сравнения строк. С его помощью можно учитывать регистр, диакритические знаки, числовые значения и игнорировать знаки препинания.
Основные параметры options:
sensitivity — определяет, учитываются ли регистр и диакритические знаки.
caseFirst — задает, какие буквы (заглавные или строчные) должны идти первыми при сортировке.
numeric — включает естественную числовую сортировку.
ignorePunctuation — позволяет игнорировать знаки препинания при сравнении.
Учет регистра (caseFirst):
Этот параметр определяет, должны ли заглавные буквы идти перед строчными или наоборот.
console.log("a".localeCompare("B", "en", { caseFirst: "upper" })); // 1 ("B" идет перед "a")
console.log("a".localeCompare("B", "en", { caseFirst: "lower" })); // -1 ("a" идет перед "B")
Доступные значения:
«upper» — заглавные буквы идут первыми.
«lower» — строчные буквы идут первыми.
«false» — порядок определяется локалью.
Чувствительность к диакритическим знакам (sensitivity)
Позволяет игнорировать или учитывать регистр и акцентные знаки, такие как «е» и «ё»
console.log("россия".localeCompare("Россия", "ru", { sensitivity: "case" })); // -1 (различает регистр)
console.log("жёлтый".localeCompare("желтый", "ru", { sensitivity: "base" })); // 0 (игнорирует диакритику)
console.log("жёлтый".localeCompare("желтый", "ru", { sensitivity: "accent" })); // 1 (различает акценты)
В первом случае различается регистр (русский символ «р» и «Р»). Во втором случае игнорируются акценты (например, «ё» и «е»). В третьем случае различаются акценты.
Доступные значения:
«base» — игнорирует регистр и диакритические знаки.
«accent» — различает акцентные знаки, но игнорирует регистр.
«case» — различает регистр, но игнорирует диакритические знаки.
«variant» — учитывает и регистр, и диакритические знаки.
Числовое сравнение (numeric)
Полезно при сортировке строк с числами, например, имен файлов.
console.log("file10".localeCompare("file2", "en", { numeric: true })); // 1 (file2 идет перед file10)
console.log("file10".localeCompare("file2", "en", { numeric: false })); // -1 (обычное посимвольное сравнение)
По умолчанию строки сравниваются посимвольно («1» идет перед «2»), но с numeric: true числа распознаются и сравниваются как целые.
Игнорирование знаков препинания (ignorePunctuation)
Позволяет не учитывать знаки препинания при сравнении строк.
console.log("hello!".localeCompare("hello", "en", { ignorePunctuation: true })); // 0
console.log("word, word".localeCompare("word word", "en", { ignorePunctuation: true })); // 0
Этот параметр полезен при обработке текста, если знаки препинания не должны влиять на порядок сортировки.
Применение localeCompare на практике (RU регион)
Метод localeCompare особенно полезен в русскоязычных проектах, так как стандартное сравнение (>, <) не учитывает особенности алфавита, регистр и числовые значения. А еще очень удобно, если нужно отсортировать числа, записанные строками. Рассмотрим несколько практических примеров.
Сортировка массива строк
При использовании sort() строки сортируются посимвольно по таблице Unicode, что может давать некорректный порядок в русском языке. localeCompare позволяет учесть локаль.
const words = ["яблоко", "Вишня", "груша", "Апельсин", "банан"];
words.sort((a, b) => a.localeCompare(b, "ru"));
console.log(words); // ["Апельсин", "банан", "Вишня", "груша", "яблоко"]
По умолчанию localeCompare чувствителен к регистру. Заглавные буквы сортируются отдельно от строчных. Чтобы этого избежать, можно использовать sensitivity: “base”.
words.sort((a, b) => a.localeCompare(b, "ru", { sensitivity: "base" })); console.log(words); // ["Апельсин", "банан", "Вишня", "груша", "яблоко"]
Сортировка объектов по строковому свойству
Частая задача — сортировка массива объектов по названию, имени или другому строковому свойству.
const users = [
{ name: "Сергей" },
{ name: "Анна" },
{ name: "Юлия" },
{ name: "Борис" }
];
users.sort((a, b) => a.name.localeCompare(b.name, "ru")); console.log(users);
/* [ { name: "Анна" }, { name: "Борис" }, { name: "Сергей" }, { name: "Юлия" } ] */
Если нужно, чтобы заглавные и строчные буквы не влияли на сортировку, добавляем sensitivity: “base”.
users.sort((a, b) => a.name.localeCompare(b.name, "ru", { sensitivity: "base" }));
Ограничения localeCompare
Хотя localeCompare — мощный инструмент для локализованного сравнения строк, он имеет ряд ограничений, о которых важно знать при использовании в реальных проектах.
Производительность на больших объемах данных
LocaleCompare работает значительно медленнее, чем стандартные операторы сравнения
(>, <), так как учитывает сложные правила локалей. При обработке больших массивов его использование может снизить производительность. Например, сортировка массива из 100 000 строк с помощью localeCompare будет ощутимо медленнее, чем при использовании стандартного Unicode-сравнения.
Альтернативы:
Если важна скорость, но не требуется строгая локализованная сортировка, можно привести строки к нижнему регистру и использовать localeCompare с sensitivity: «base», что немного ускорит процесс.
Для англоязычных данных и технических строк можно использовать обычные операторы сравнения.
В случае частого использования стоит кешировать результаты сравнения.
Ограниченная поддержка локалей в старых браузерах
Хотя современные браузеры хорошо поддерживают localeCompare, в устаревших версиях могут возникать проблемы.
Вот так можно проверить доступные локали
console.log(Intl.Collator.supportedLocalesOf(["ru", "en", "fr"]));
Если браузер не поддерживает указанную локаль, результат сортировки может отличаться от ожидаемого.
Альтернатива:
Использовать Intl.Collator, который иногда работает быстрее и предоставляет больше возможностей.
const collator = new Intl.Collator("ru", { sensitivity: "base" });
arr.sort((a, b) => collator.compare(a, b));
Вывод
localeCompare — удобный метод для локализованного сравнения строк, но в некоторых случаях его использование может быть неэффективным. Для ускорения сортировки или поиска на больших данных стоит рассмотреть Intl.Collator, предварительную нормализацию данных или специализированные библиотеки.