Работа с текстом на естественных языках требует учета того, что «символ» в привычном смысле не всегда соответствует минимальной единице отображения или смыслового деления. В Unicode один видимый символ может состоять из нескольких кодовых точек: базового символа и комбинируемых диакритических знаков, эмодзи могут образовываться последовательностями, а границы слов и предложений зависят от языка и контекста.
В JavaScript для корректной сегментации текста используется объект Intl.Segmenter, входящий в состав Internationalization API. Он предоставляет стандартизированный механизм разбиения текста на:
Основное преимущество подхода — соответствие стандарту Unicode Text Segmentation (UAX #29), что обеспечивает корректную обработку сложных языковых конструкций.
Объект сегментации создается через конструктор:
const segmenter = new Intl.Segmenter(locale, options);
locale Определяет языковую локаль, влияющую на правила разбиения. Например:
"en" — английский"ru" — русский"ja" — японскийЕсли передано "und" или значение не указано,
используется нейтральная локаль по умолчанию.
options — ключевой объект конфигурации:
granularity — уровень сегментации:
"grapheme""word""sentence"Графемная сегментация разделяет текст на минимальные визуальные единицы, которые пользователь воспринимает как один символ.
const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
const text = "á??";
const segments = segmenter.segment(text);
for (const { segment } of segments) {
console.log(segment);
}
Результат будет учитывать:
á как единый графемный кластер (буква +
диакритика)Это критично для UI-компонентов, где индексация по символам может ломать отображение текста.
Сегментация на слова учитывает языковые правила разделения слов и знаков препинания.
const segmenter = new Intl.Segmenter("ru", { granularity: "word" });
const text = "JavaScript — мощный язык.";
const segments = segmenter.segment(text);
Каждый сегмент представляет объект:
{
segment: "JavaScript",
index: 0,
isWordLike: true
}
isWordLiketrue — сегмент является словом или числовым
токеномfalse — пробелы, знаки пунктуации,
символы-разделителиПример обработки:
for (const part of segments) {
if (part.isWordLike) {
console.log(part.segment);
}
}
Разные языки имеют разные правила:
Сегментация на предложения используется для анализа текста, NLP-задач и разбиения длинных текстов.
const segmenter = new Intl.Segmenter("en", { granularity: "sentence" });
const text = "Hello world. How are you doing today? Great!";
const segments = segmenter.segment(text);
Каждый элемент соответствует целому предложению:
Результат segmenter.segment() является итерируемым
объектом:
const segmenter = new Intl.Segmenter("ru", { granularity: "word" });
const text = "Привет, мир!";
for (const { segment, index } of segmenter.segment(text)) {
console.log(index, segment);
}
Поле index указывает позицию начала сегмента в исходной
строке в UTF-16 единицах.
Это важно при:
function highlightWords(text) {
const segmenter = new Intl.Segmenter("ru", { granularity: "word" });
return [...segmenter.segment(text)]
.map(part => part.isWordLike ? `[${part.segment}]` : part.segment)
.join("");
}
Обычное slice ломает emoji и комбинированные символы.
Корректный вариант:
function truncateByGraphemes(text, max) {
const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
const segments = [...segmenter.segment(text)];
return segments.slice(0, max).map(s => s.segment).join("");
}
function splitSentences(text, locale = "en") {
const segmenter = new Intl.Segmenter(locale, { granularity: "sentence" });
return [...segmenter.segment(text)].map(s => s.segment);
}
Механизм основан на стандарте Unicode, который определяет:
В отличие от самодельных решений на RegExp:
text.split(/\s+/)
Ограничения:
[...text]
Проблема:
Поддержка зависит от версии движка:
В старых окружениях возможна необходимость полифиллов, однако точная эмуляция UAX #29 требует значительных ресурсов и часто реализуется частично.
Отсутствие пробелов требует:
Несмотря на мощность, существуют ограничения:
Поведение можно обобщить следующим образом:
Механизм обеспечивает единообразную обработку текста в разных языках и сценариях, устраняя необходимость ручной реализации токенизации и учета сложных Unicode-особенностей.