Normalize: примеры (JAVASCRIPT)

Нормализация строк с помощью метода normalize в JavaScript
Раздел: Строки, Юникод
normalize(form?): string

Основные сведения о функции normalize

Метод normalize() принадлежит объекту String в JavaScript. Его основное назначение — приведение строки к одной из стандартных форм нормализации Юникода (Unicode). Нормализация используется для обеспечения единообразного представления текста, состоящего из символов, которые могут быть записаны различными способами (например, с использованием комбинирующихся диакритических знаков).

Функция вызывается для строки и принимает один необязательный аргумент — форму нормализации:

  • form (необязательный) — строка, указывающая форму нормализации. Допустимые значения: 'NFC', 'NFD', 'NFKC', 'NFKD'. Если аргумент опущен или равен undefined, используется 'NFC'.

Возвращаемое значение — новая строка, представляющая нормализованную форму исходной строки согласно указанной форме. Если значение аргумента form не является допустимым, генерируется исключение RangeError.

Описание форм нормализации:

  • NFC (Normalization Form Canonical Composition) — каноническая композиция. Символы по возможности представляются в виде единых составных символов (например, 'é' как один символ). Это форма по умолчанию.
  • NFD (Normalization Form Canonical Decomposition) — каноническая декомпозиция. Символы раскладываются на базовые символы и комбинирующиеся знаки (например, 'é' на 'e' и комбинирующийся acute accent).
  • NFKC (Normalization Form Compatibility Composition) — совместимая композиция. Сначала применяется декомпозиция совместимости, затем каноническая композиция. Эта форма заменяет совместимые символы (например, лигатуры, стилистические варианты) их эквивалентами.
  • NFKD (Normalization Form Compatibility Decomposition) — совместимая декомпозиция. Применяется декомпозиция совместимости, при которой совместимые символы заменяются.

Использование функции актуально при сравнении строк, сортировке, поиске, хранении текста, а также при работе с текстом на разных языках, содержащим диакритические знаки.

Простыe случаи применения

Пример с различными формами нормализации для символа с диакритическим знаком:

let str = 'café';
// Символ 'é' может быть представлен как U+00E9 или как U+0065 + U+0301
console.log(str.normalize('NFC')); // 'café' (композиция)
console.log(str.normalize('NFD')); // 'café' (декомпозиция - базовый символ и комбинирующийся знак)
'café'
'café'

Пример с совместимыми символами (римская цифра):

let roman = 'Ⅳ'; // Римская цифра 4 (один символ)
console.log(roman.normalize('NFKC')); // Заменяется на 'IV'
console.log(roman.normalize('NFKD')); // Также 'IV'
'IV'
'IV'

Пример с опущенным аргументом:

let word = 'naïve';
console.log(word.normalize()); // Используется NFC по умолчанию
'naïve'

Аналогичные функции в JavaScript

Прямых аналогов функции normalize() в JavaScript нет, так как ее задача специфична. Однако для некоторых смежных задач могут применяться другие методы.

  • String.prototype.localeCompare() — выполняет сравнение строк с учетом языка и региональных настроек. Может учитывать особенности символов, но не выполняет нормализацию. Используется для корректной сортировки строк.
  • Intl.Collator — объект, предоставляющий более гибкое сравнение строк с учетом локали. Позволяет задавать чувствительность к регистру, диакритическим знакам и другим параметрам. Нормализацию не производит, но может работать с уже нормализованными строками для повышения точности сравнения.

В случаях, когда требуется именно приведение к канонической форме Юникода, используется только normalize(). Для сравнения строк, которые могут иметь разное представление символов, предварительная нормализация и последующее сравнение (например, через === или localeCompare) является предпочтительным подходом.

Распространенные ошибки

1. Передача недопустимого значения формы нормализации. Генерируется исключение RangeError.

try {
    'text'.normalize('INVALID');
} catch (e) {
    console.log(e.name + ': ' + e.message);
}
RangeError: The normalization form should be one of NFC, NFD, NFKC, NFKD.

2. Предположение, что нормализация изменяет исходную строку. Метод возвращает новую строку, исходная остается неизменной.

let original = 'café';
let normalized = original.normalize('NFD');
console.log(original); // 'café'
console.log(normalized); // 'café'
'café'
'café'

3. Использование нормализации для всех задач сравнения строк без учета локали. Для сортировки или сравнения с учетом правил языка требуется localeCompare или Intl.Collator даже после нормализации.

let a = 'café';
let b = 'café'; // Разное представление
console.log(a === b); // false
console.log(a.normalize('NFC') === b.normalize('NFC')); // true
false
true

История изменений

Метод normalize() был добавлен в стандарт ECMAScript 6 (ES2015). С момента внедрения спецификация функции не претерпевала значительных изменений в основных браузерах и средах выполнения JavaScript.

Важные моменты:

  • Функция стала частью языка с ES6. До этого требовались сторонние библиотеки для нормализации.
  • Поведение и поддерживаемые формы нормализации соответствуют стандарту Unicode. Актуальные версии JavaScript следуют последним версиям стандарта Unicode, что может влиять на обработку некоторых символов в новых версиях движков.
  • Поддержка функции в старых браузерах (например, Internet Explorer) отсутствует или может быть неполной. Для совместимости может потребоваться использование полифилов.

Рекомендуется проверять поддержку в целевых средах выполнения, если важна работа с устаревшими системами.

Расширенные примеры использования

Пример 1: Нормализация перед сравнением строк для поиска.

Пример javascript
let searchTerm = 'café'.normalize('NFC'); // Приводим к единой форме
let items = ['café', 'cafe', 'coffee'];
let results = items.filter(item => item.normalize('NFC') === searchTerm);
console.log(results); // ['café']
['café']

Пример 2: Подсчет символов с учетом нормализации. Без нормализации символ, представленный двумя кодовыми точками (например, 'e' + комбинирующийся знак), будет считаться за два символа.

Пример javascript
let str = 'café'; // 'e' + U+0301
console.log(str.length); // 5
console.log(str.normalize('NFC').length); // 4 (символ 'é' как один)
5
4

Пример 3: Удаление диакритических знаков через нормализацию NFD и фильтрацию.

Пример javascript
function removeDiacritics(str) {
    return str.normalize('NFD')
              .replace(/[\u0300-\u036f]/g, ''); // Удаляем комбинирующиеся диакритические знаки
}
console.log(removeDiacritics('cliché')); // 'cliche'
console.log(removeDiacritics('naïve'));  // 'naive'
'cliche'
'naive'

Пример 4: Работа с эмодзи и специальными символами. Некоторые эмодзи состоят из нескольких кодовых точек, и нормализация может на них влиять.

Пример javascript
let emoji = '❤️';
console.log(emoji.normalize('NFD').length); // Может отличаться в зависимости от представления
2

Пример 5: Использование NFKC для приведения текста к совместимой форме, что полезно для идентификаторов или URL.

Пример javascript
let text = '¹²³'; // Надстрочные цифры
console.log(text.normalize('NFKC')); // '123' (обычные цифры)
'123'

Нормализация в других языках программирования

Концепция нормализации Юникода присутствует во многих языках программирования, часто в составе библиотек для работы с Unicode.

Python (модуль unicodedata):

import unicodedata
str = 'café'
print(unicodedata.normalize('NFC', str))  # 'café'
print(unicodedata.normalize('NFD', str))  # 'café'
café
café

PHP (класс Normalizer):

$str = 'café';
echo Normalizer::normalize($str, Normalizer::FORM_C); // 'café'
echo Normalizer::normalize($str, Normalizer::FORM_D); // 'café'
café
café

Java (класс java.text.Normalizer):

String str = "café";
String nfc = Normalizer.normalize(str, Normalizer.Form.NFC); // "café"
String nfd = Normalizer.normalize(str, Normalizer.Form.NFD); // "café"
café
café

MySQL (функции NORMALIZE() и WF_NORMALIZE_STRING()): Нормализация доступна в некоторых контекстах, например, для полнотекстового поиска или сравнения. Конкретный синтаксис зависит от версии и настроек сервера.

Основное отличие реализации в JavaScript — это метод, встроенный в объект String, что делает его использование очень простым. В других языках обычно требуется импорт отдельного модуля или класса.

JS normalize function comments

En
Normalize Returns the Unicode Normalization Form of the string