Как в 1С подсчитать количество уникальных слов в тексте без учета регистра?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработчика 1С часто возникают задачи, связанные с анализом текстовой информации: от простых проверок заполнения до сложных алгоритмов поиска дублей или анализа частотности слов. Одной из базовых, но важных задач является подсчет уникальных слов в произвольном тексте. Разберем подробно, как реализовать этот функционал наиболее эффективно, используя встроенные инструменты платформы 1С:Предприятие 8.3.

Постановка задачи и проектирование интерфейса

Прежде чем переходить к написанию кода, определимся с инструментарием. Нам необходимо создать внешнюю обработку, которая будет принимать текст от пользователя и выдавать результат. Для этого проанализируем необходимые объекты формы:

  1. Реквизит обработки: Создадим реквизит Текст с типом Строка. В свойствах элемента формы обязательно установим флаг Многострочный режим, чтобы пользователь мог вставлять большие фрагменты текста с переносами строк.
  2. Команда: Создадим команду Подсчитать и разместим ее на форме в виде кнопки.

Алгоритм решения через коллекцию «Соответствие»

Рассмотрим наиболее производительный способ решения задачи, предложенный в обсуждении. Использование объекта Соответствие (Map) идеально подходит для поиска уникальных значений, так как поиск по ключу в этой коллекции выполняется крайне быстро благодаря механизмам хеширования. В отличие от Структуры, в Соответствии ключом может быть строка любого вида, включая строки с пробелами или цифрами в начале.

Разберем процесс выполнения по шагам:

  1. Подготовка строки: Чтобы подсчет не зависел от регистра (например, слова "Мир" и "мир" считались одинаковыми), приведем весь текст к одному регистру заранее.
  2. Разбиение на слова: Используем мощную функцию СтрРазделить, которая превратит текст в массив подстрок.
  3. Исключение дублей: Обойдем массив и добавим каждое слово в Соответствие.
  4. Вывод результата: Количество элементов в коллекции и будет числом уникальных слов.

Проанализируем программный код реализации:


&НаКлиенте
Процедура Подсчитать(Команда)
    
    // Приводим текст к нижнему регистру один раз для оптимизации
    ТекстНижнийРегистр = НРег(Объект.Текст);
    
    // Определяем разделители (пробел, знаки препинания, переносы строк)
    Разделители = " ,.!?;:-()"""; 
    
    // Разделяем строку в массив. 
    // Ложь в третьем параметре исключает пустые строки из результата
    МассивСлов = СтрРазделить(ТекстНижнийРегистр, Разделители, Ложь);
    
    // Используем Соответствие для хранения уникальных ключей
    УникальныеСлова = Новый Соответствие;
    
    Для Каждого Слово Из МассивСлов Цикл
        // Метод Вставить просто перезапишет значение, если ключ уже есть.
        // Количество элементов в Соответствии увеличится только для новых слов.
        УникальныеСлова.Вставить(Слово, Истина);
    КонецЦикла;
    
    КоличествоУникальных = УникальныеСлова.Количество();
    
    Сообщить(СтрШаблон("Количество уникальных слов в тексте: %1", КоличествоУникальных));
    
КонецПроцедуры

Почему мы используем СтрРазделить и Соответствие?

Рассмотрим подробнее технические нюансы этого решения. Функция СтрРазделить появилась в платформе 8.3.6 и работает значительно быстрее, чем старые алгоритмы ручного перебора символов строки в цикле. Важным моментом является третий параметр ВключатьПустые. Если в тексте встречаются два пробела подряд, при значении Истина функция вернет пустую строку в массиве, что исказит наш результат. Установка значения Ложь избавляет нас от лишних проверок Если ЗначениеЗаполнено(Слово) внутри цикла.

Выбор Соответствия обусловлен тем, что при добавлении элемента методом Вставить система сама проверяет наличие ключа. Если слово уже встречалось, оно просто обновит значение по этому ключу, не создавая новой записи. В итоге УникальныеСлова.Количество() вернет именно число неповторяющихся слов.

Оптимизация приведения к регистру

В ходе дискуссии на форуме возник спор: где лучше вызывать функцию НРег()? Выясним причину, по которой вариант из нашего примера (вызов перед циклом) предпочтительнее. Если мы будем вызывать НРег(Слово) внутри цикла, то функция будет выполнена столько раз, сколько слов в тексте (например, 10 000 раз). Если же мы вызовем ее один раз для всей строки, это значительно сэкономит ресурсы процессора, так как вызов программного интерфейса встроенного языка — это относительно "дорогая" операция.

Альтернативный метод: Использование Таблицы Значений

Некоторые разработчики предпочитают использовать ТаблицуЗначений. Рассмотрим этот способ, так как он может быть полезен, если в дальнейшем вам нужно не только посчитать количество, но и, например, отсортировать слова по алфавиту или вывести их в отчет.

Посмотрим на пример кода:


// Создаем таблицу
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Слово");

// Заполняем таблицу из массива
Для Каждого Слово Из МассивСлов Цикл
    НоваяСтрока = ТЗ.Добавить();
    НоваяСтрока.Слово = Слово;
КонецЦикла;

// Сворачиваем таблицу по колонке Слово
ТЗ.Свернуть("Слово");

// Результат - количество строк после сворачивания
КоличествоУникальных = ТЗ.Количество();

Этот метод кажется наглядным, однако стоит учитывать, что создание объекта ТаблицаЗначений и выполнение метода Свернуть требует больше оперативной памяти и времени, чем работа с Соответствием. Кроме того, ТаблицаЗначений доступна только на стороне сервера, что потребует лишнего контекстного вызова, если обработка текста происходит на клиенте.

Тонкости обработки знаков препинания

Проанализируем ситуацию: если пользователь введет текст "Привет, мир! Привет мир.", то при разделении только по пробелу мы получим слова "Привет,", "мир!", "Привет", "мир.". Для программы это четыре разных слова. Чтобы решение было качественным, в переменную Разделители функции СтрРазделить необходимо включить все возможные символы, которые не являются буквами.

Важный совет: В 1С СтрРазделить воспринимает каждый символ в строке разделителей как отдельный разделитель. Поэтому строка " ,.!?;:" корректно обработает большинство текстов. Для более сложного и гибкого выделения слов и разделителей по шаблонам подойдёт подсистема для работы с регулярными выражениями в 1С.

Подводя итог, можно сказать, что связка НРег() + СтрРазделить() + Соответствие является "золотым стандартом" для подобных задач в 1С благодаря своей лаконичности и высокой скорости работы. При необходимости можно использовать готовую обработку для подсчета количества слов в тексте и их вывода.

← На главную