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

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

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

Базовый алгоритм с использованием массива

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

Проанализируем первый предложенный вариант кода:


Функция ПосчитатьКоличествоРазличныхСимволовКириллицы(Знач СтрокаПарсинга) Экспорт
    МассивНайденныхРазличныхСимволов = Новый Массив;
    СтрокаПарсинга = СокрЛП(СтрокаПарсинга);
    СтрокаПарсинга = нрег(СтрокаПарсинга);
    ДлинаСтрокиПарсинга = СтрДлина(СтрокаПарсинга);
    
    Если ДлинаСтрокиПарсинга > 0 Тогда
        СимволыКириллицы = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
        Для а = 1 по ДлинаСтрокиПарсинга Цикл
            ТекущийСимволСтроки = Сред(СтрокаПарсинга, а, 1);
            Если МассивНайденныхРазличныхСимволов.Найти(ТекущийСимволСтроки) = Неопределено 
                 И СтрНайти(СимволыКириллицы, ТекущийСимволСтроки) > 0 Тогда
                МассивНайденныхРазличныхСимволов.Добавить(ТекущийСимволСтроки);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
    Возврат МассивНайденныхРазличныхСимволов.Количество();
КонецФункции

Несмотря на простоту, в этом коде есть два важных нюанса. Во-первых, важно не забыть про букву й и ё, которые иногда выпадают из подобных строк-эталонов. Во-вторых, метод Найти() для массива работает медленно на больших объемах данных, так как при каждой итерации программа вынуждена заново перебирать весь массив в поисках дубля.

Оптимизация через объект «Соответствие»

Выясним причину низкой производительности предыдущего метода. Проблема заключается в линейном поиске в массиве. Чтобы ускорить процесс, проанализируем ситуацию и применим объект Соответствие. В 1С поиск по ключу в Соответствие реализован через хеш-таблицы, что значительно быстрее, чем поиск в массиве.

Рассмотрим улучшенный вариант функции:


Функция ПосчитатьУникальныеКириллицу(Знач СтрокаПарсинга) Экспорт
    Соот = Новый Соответствие;
    СимволыКириллицы = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
    СтрокаПарсинга = нрег(СтрокаПарсинга);
    
    Для сч = 1 по СтрДлина(СтрокаПарсинга) Цикл
        СимвКир = Сред(СтрокаПарсинга, сч, 1);
        Если СтрНайти(СимволыКириллицы, СимвКир) > 0 Тогда
            // Ключ уникален в соответствии по определению
            Соот.Вставить(СимвКир, Истина);
        КонецЕсли;
    КонецЦикла;
    
    Возврат Соот.Количество();
КонецФункции

Этот метод работает гораздо стабильнее. Даже если в строке будет миллион символов, проверка Соот.Вставить не потребует полного перебора коллекции, в отличие от метода Массив.Найти().

Фильтрация строки через «СтрРазделить» и «СтрСоединить»

Посмотрим на пример гибридного решения. Иногда выгоднее сначала "очистить" строку от всего лишнего (латиницы, цифр, пробелов), а уже потом считать уникальные знаки в чистой кириллической последовательности. Это позволяет уменьшить количество итераций в основном цикле обработки уникальности.

Разберем по шагам алгоритм фильтрации:

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

СимволыКириллицы = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
СимволыКириллицы = СимволыКириллицы + ВРЕГ(СимволыКириллицы);

// Убираем всё, что НЕ кириллица
МассивСтрокНеКириллицы = СтрРазделить(СтрокаПарсинга, СимволыКириллицы, Истина);
СтрокиНеКириллицы = СтрСоединить(МассивСтрокНеКириллицы);

// Теперь получаем только кириллицу
МассивСтрокКириллицы = СтрРазделить(СтрокаПарсинга, СтрокиНеКириллицы, Ложь);
ЧистаяКириллица = СтрСоединить(МассивСтрокКириллицы);

// Считаем уникальные через Соответствие
Соот = Новый Соответствие;
Для сч = 1 по СтрДлина(ЧистаяКириллица) Цикл
    Симв = Сред(ЧистаяКириллица, сч, 1);
    Соот.Вставить(нрег(Симв), Истина);
КонецЦикла;

Профессиональный подход: регулярные выражения и Unicode

Если нам требуется максимальная скорость, особенно при работе с большими текстами (например, анализ целой книги), стоит рассмотреть низкоуровневые способы или использование COM-объектов.

1. Использование регулярных выражений (RegExp)

Регулярные выражения позволяют мгновенно отсечь все символы, не входящие в диапазон [а-яёА-ЯЁ]. В среде Windows это можно сделать через объект VBScript.RegExp. Преимущество в том, что движок регулярных выражений написан на C++ и оптимизирован для поиска паттернов гораздо лучше, чем встроенный язык 1С.

2. Проверка кодов символов (Unicode)

Вместо использования функции СтрНайти внутри цикла, что заставляет платформу каждый раз искать подстроку в строке-шаблоне, мы можем сравнивать числовые коды символов. Коды кириллицы в Unicode расположены плотно. Основной блок букв (А-я) находится в диапазоне от 1040 до 1103. Исключением являются буквы Ё (код 1025) и ё (код 1105).

Проанализируем пример функции с проверкой кодов:


Функция ЭтоКириллица(Символ)
    Код = КодСимвола(Символ);
    // Проверка основного диапазона и буквы Ё
    Возврат (Код >= 1040 И Код <= 1103) Или Код = 1025 Или Код = 1105;
КонецФункции

Сравнение чисел — это самая быстрая операция. Использование такой проверки в цикле вместе с Соответствие даст наилучший результат по скорости на платформе 1С.

Современные возможности платформы (8.3.10+)

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

Разберем комплексное, наиболее эффективное решение:


Функция ПодсчитатьУникальнуюКириллицуОптимизированно(Знач ВходнаяСтрока) Экспорт
    Результат = Новый Соответствие;
    
    // Преобразуем строку в массив символов сразу (для платформ 8.3.10+)
    ВсеСимволы = СтрРазделить(нрег(ВходнаяСтрока), "");
    
    Для Каждого ТекущийСимвол Из ВсеСимволы Цикл
        Код = КодСимвола(ТекущийСимвол);
        // Проверяем, что символ - кириллица
        Если (Код >= 1072 И Код <= 1103) Или Код = 1105 Тогда
            Результат.Вставить(ТекущийСимвол, Истина);
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат.Количество();
КонецФункции

В данном примере мы использовали диапазон 1072–1103, так как предварительно привели строку к нижнему регистру функцией нрег(). Это избавляет от необходимости проверять коды заглавных букв.

Итоги и рекомендации

Мы проанализировали различные методы решения задачи. Подведем итоги:

  1. Для коротких строк (например, ФИО контрагента) подойдет любой метод, даже самый первый с массивом.
  2. Для средних текстов используйте Соответствие и метод Сред().
  3. Для высоконагруженных систем и больших текстов используйте СтрРазделить(Строка, "") и проверку кодов КодСимвола().
  4. Не забывайте про специфику кодировок: буква Ё всегда стоит особняком в таблице Unicode, и её нужно обрабатывать отдельно.

Выбор конкретного метода зависит от версии вашей платформы и объема обрабатываемых данных. Использование Соответствие вместо Массив является "золотым стандартом" при поиске уникальных значений в 1С.

← На главную