Объект Intl.Segmenter предназначен для разбиения текста
на логические сегменты с учётом языковых правил. В отличие от обычных
методов работы со строками (split, substring,
регулярные выражения), сегментация учитывает особенности письменности,
пробелов, пунктуации и Unicode-символов.
API особенно важен для:
Поддерживаются три уровня сегментации:
grapheme — отдельные визуальные символы;word — слова;sentence — предложения.Синтаксис:
const segmenter = new Intl.Segmenter(locales, options);
| Параметр | Описание |
|---|---|
locales |
Язык или массив языков |
options |
Настройки сегментации |
Главная настройка:
{
granularity: "grapheme" | "word" | "sentence"
}
Пример:
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
segment()После создания сегментатора вызывается метод:
segmenter.segment(text)
Он возвращает специальный итерируемый объект
Segments.
Пример:
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
const segments = segmenter.segment("Привет мир");
for...ofНаиболее распространённый способ перебора сегментов:
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
const text = "JavaScript очень удобен.";
for (const item of segmenter.segment(text)) {
console.log(item);
}
Результат:
{
segment: 'JavaScript',
index: 0,
input: 'JavaScript очень удобен.',
isWordLike: true
}
{
segment: ' ',
index: 10,
input: 'JavaScript очень удобен.',
isWordLike: false
}
Каждый элемент содержит несколько свойств.
segmentТекущий фрагмент текста.
item.segment
Пример:
console.log(item.segment);
indexПозиция сегмента в исходной строке.
console.log(item.index);
Пример:
const text = "Привет мир";
for (const item of segmenter.segment(text)) {
console.log(item.segment, item.index);
}
Результат:
Привет 0
7
мир 8
inputИсходная строка.
console.log(item.input);
Полезно при работе с несколькими источниками текста.
isWordLikeСвойство доступно только при granularity: "word".
Оно показывает, является ли сегмент словом.
console.log(item.isWordLike);
При сегментации по словам пробелы и знаки пунктуации тоже становятся сегментами.
Пример:
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
const text = "Привет, мир!";
for (const item of segmenter.segment(text)) {
console.log(item.segment, item.isWordLike);
}
Результат:
Привет true
, false
false
мир true
! false
Получение только слов:
const words = [];
for (const item of segmenter.segment(text)) {
if (item.isWordLike) {
words.push(item.segment);
}
}
console.log(words);
Результат:
["Привет", "мир"]
Графема — визуальный символ, который пользователь воспринимает как один знак.
В Unicode один символ может состоять из нескольких кодовых точек.
Пример:
const text = "??";
Этот символ состоит из:
Обычная работа со строками может разбить его неправильно.
const segmenter = new Intl.Segmenter("ru", {
granularity: "grapheme"
});
const text = "A??Б";
for (const item of segmenter.segment(text)) {
console.log(item.segment);
}
Результат:
A
??
Б
Обычный перебор:
const text = "??";
console.log(text.length);
Результат:
4
Перебор по индексам:
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
Даёт некорректное разбиение.
Использование Intl.Segmenter решает эту проблему.
const segmenter = new Intl.Segmenter("ru", {
granularity: "sentence"
});
const text = `
JavaScript очень популярен.
Intl API упрощает локализацию.
Segmenter работает с Unicode.
`;
for (const item of segmenter.segment(text)) {
console.log(item.segment);
}
Результат:
JavaScript очень популярен.
Intl API упрощает локализацию.
Segmenter работает с Unicode.
Алгоритм учитывает:
Пример:
const text = "г. Москва находится в России.";
Разбиение будет корректным, несмотря на сокращение
г..
Array.fromОбъект Segments итерируемый, поэтому его можно
преобразовать в массив.
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
const segments = Array.from(
segmenter.segment("Привет мир")
);
console.log(segments);
const parts = Array.from(
segmenter.segment("Привет мир"),
item => item.segment
);
console.log(parts);
Результат:
["Привет", " ", "мир"]
const result = [
...segmenter.segment("JavaScript")
];
console.log(result);
next()Можно получить итератор напрямую.
const iterator =
segmenter.segment("Привет")[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
Результат:
{
value: {
segment: 'Привет',
index: 0,
input: 'Привет',
isWordLike: true
},
done: false
}
break
и continuefor (const item of segmenter.segment(text)) {
if (item.segment === ".") {
break;
}
console.log(item.segment);
}
for (const item of segmenter.segment(text)) {
if (!item.isWordLike) {
continue;
}
console.log(item.segment);
}
function hasWord(text, target) {
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
for (const item of segmenter.segment(text)) {
if (
item.isWordLike &&
item.segment === target
) {
return true;
}
}
return false;
}
console.log(
hasWord("JavaScript прекрасен", "прекрасен")
);
function countWords(text) {
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
let count = 0;
for (const item of segmenter.segment(text)) {
if (item.isWordLike) {
count++;
}
}
return count;
}
console.log(
countWords("JavaScript очень удобен")
);
Результат:
3
Свойство index позволяет находить позиции слов.
const text = "Привет мир";
for (const item of segmenter.segment(text)) {
if (item.isWordLike) {
console.log(
item.segment,
item.index
);
}
}
Результат:
Привет 0
мир 8
const segmenter = new Intl.Segmenter("ru", {
granularity: "sentence"
});
const iterator =
segmenter.segment(text)[Symbol.iterator]();
const first = iterator.next().value;
console.log(first.segment);
Некоторые языки не используют пробелы между словами.
Например:
Intl.Segmenter умеет корректно выделять слова.
Пример для японского языка:
const segmenter = new Intl.Segmenter("ja", {
granularity: "word"
});
const text = "私は学生です";
for (const item of segmenter.segment(text)) {
if (item.isWordLike) {
console.log(item.segment);
}
}
Возможный результат:
私
は
学生
です
Создание объекта Intl.Segmenter может быть относительно
затратным.
Лучше создавать его один раз:
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
function parse(text) {
return Array.from(segmenter.segment(text));
}
Менее эффективно:
const result = [
...segmenter.segment(text)
];
Более эффективно:
for (const item of segmenter.segment(text)) {
// обработка
}
Без промежуточного массива уменьшается расход памяти.
Intl.Segmenter поддерживается в:
Проверка поддержки:
if (Intl.Segmenter) {
console.log("Поддерживается");
}
function tokenize(text) {
const segmenter = new Intl.Segmenter("ru", {
granularity: "word"
});
const tokens = [];
for (const item of segmenter.segment(text)) {
if (item.isWordLike) {
tokens.push({
word: item.segment,
position: item.index
});
}
}
return tokens;
}
console.log(
tokenize("JavaScript очень мощный язык")
);
Результат:
[
{ word: 'JavaScript', position: 0 },
{ word: 'очень', position: 11 },
{ word: 'мощный', position: 17 },
{ word: 'язык', position: 25 }
]