Привет, меня зовут Дмитрий, я 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, предварительную нормализацию данных или специализированные библиотеки.

Комментарии (0)