Современные задачи обработки текста в JavaScript требуют учета
языковых особенностей, выходящих за рамки простого разбиения строки по
символу точки. Пунктуация, сокращения, многоточия, аббревиатуры и
различия между языками делают наивные алгоритмы нестабильными. Intl API
предоставляет стандартизированный механизм сегментации текста через
Intl.Segmenter, где одним из ключевых режимов является
разбиение на предложения.
Сегментация на уровне предложений рассматривает текст как последовательность лингвистических единиц, а не как набор символов. Это позволяет корректно учитывать контекст языка и правила пунктуации.
Ключевой механизм: Intl.Segmenter с
параметром granularity: "sentence"
Сегментатор создаётся с указанием локали и уровня детализации:
const segmenter = new Intl.Segmenter("ru", { granularity: "sentence" });
"ru" — локаль, влияющая на правила определения границ
предложенийgranularity: "sentence" — режим разбиения текста на
предложенияВ зависимости от локали могут отличаться правила обработки сокращений, кавычек и границ предложений.
Сегментатор не возвращает готовый массив строк. Вместо этого он выдаёт итерируемую последовательность сегментов, где каждый элемент содержит:
const text = "Привет! Как дела? Всё работает корректно.";
const segments = segmenter.segment(text);
for (const s of segments) {
console.log(s.segment, s.index, s.input);
}
Каждый элемент представляет одно предложение или его логически завершённую часть.
Разбиение не сводится к поиску символов .,
!, ?. Используются правила Unicode Text
Segmentation:
Пример неоднозначного случая:
const text = "Он сказал: «Привет. Как дела?» и ушёл.";
Результат корректной сегментации:
Разные языки используют разные правила завершения предложений.
const segmenterEn = new Intl.Segmenter("en", { granularity: "sentence" });
Особенности:
const segmenterJa = new Intl.Segmenter("ja", { granularity: "sentence" });
Результат работы сегментера является ленивым итератором:
const text = "Первое предложение. Второе предложение. Третье.";
const segments = [...segmenter.segment(text)];
console.log(segments);
Каждый элемент:
{
segment: "Первое предложение.",
index: 0,
input: "Первое предложение. Второе предложение. Третье."
}
Часто требуется получить только текст без метаданных:
const sentences = [];
for (const { segment } of segmenter.segment(text)) {
sentences.push(segment);
}
Итоговый массив содержит список предложений, корректно выделенных по языковым правилам.
Индексы позволяют выполнять точное позиционирование в исходной строке:
for (const s of segmenter.segment(text)) {
console.log(text.slice(s.index, s.index + s.segment.length));
}
Это важно при:
const text = "Я не уверен... возможно, это так.";
Многоточие не всегда считается концом предложения, особенно при отсутствии заглавной буквы после него.
const text = "Это случилось в г. Москве. Потом всё изменилось.";
Сокращение «г.» не должно разрывать предложение.
const text = "Он сказал: \"Я приду завтра.\" И ушёл.";
Закрывающие кавычки влияют на определение конца предложения, особенно в английской локали.
Типичный подход:
text.split(".")
Проблемы:
! и ?Intl Segmenter решает эти проблемы за счёт использования ICU правил.
Intl.Segmenter основан на ICU (International Components
for Unicode), что обеспечивает:
Сегментация выполняется на уровне движка, а не через JavaScript-реализацию.
Сегментация предложений часто используется вместе с:
Intl.DateTimeFormat для локализованных текстов с
датамиIntl.NumberFormat для вставки чисел в текстIntl.PluralRules для грамматически корректных формПример комбинированной обработки текста:
const formatter = new Intl.NumberFormat("ru");
const text = `У вас 5 сообщений. Их нужно прочитать.`;
const segmenter = new Intl.Segmenter("ru", { granularity: "sentence" });
for (const { segment } of segmenter.segment(text)) {
console.log(segment);
}
Несмотря на это, поведение остаётся значительно более предсказуемым, чем у ручных алгоритмов.