При разработке на платформе 1С:Предприятие часто возникают задачи, связанные с нестандартным текстовым анализом. Одной из классических задач, которая нередко встречается на технических собеседованиях или в учебных заданиях, является подсчет количества вхождений определенного символа (например, буквы «а») в строке без использования штатной функции СтрЧислоВхождений. При необходимости более сложного анализа можно воспользоваться инструментом для подсчета количества слов в тексте.
В этой статье мы подробно разберем несколько эффективных способов решения этой задачи. Мы проанализируем различные алгоритмические подходы — от простых посимвольных циклов до использования регулярных выражений и манипуляций с длиной строки, а также разберем критически важные нюансы, такие как чувствительность к регистру, наличие визуально похожих латинских символов и производительность каждого метода.
Давайте рассмотрим наиболее изящный алгоритм, который не требует организации ресурсоемких циклов в коде 1С. Суть метода заключается в следующем: мы измеряем длину исходной текстовой строки, затем удаляем из нее все целевые символы (в нашем случае букву «а») с помощью функции СтрЗаменить, после чего снова измеряем длину. Разница между первоначальной и новой длиной и будет равна количеству удаленных символов.
Посмотрим на практическую реализацию этого метода:
Функция КолБуквРазницаДлин(ИсходнаяСтрока)
ДлинаИсходная = СтрДлина(ИсходнаяСтрока);
СтрокаБезБукв = СтрЗаменить(ИсходнаяСтрока, "а", "");
ДлинаПослеЗамены = СтрДлина(СтрокаБезБукв);
Возврат ДлинаИсходная - ДлинаПослеЗамены;
КонецФункции
Преимущества метода:
Если вам требуется продемонстрировать базовое владение алгоритмическим мышлением или подробно контролировать процесс обработки каждого символа (например, собирать дополнительную статистику), отлично подойдет посимвольный перебор. Мы организуем цикл от первого до последнего символа строки и с помощью функции Сред извлекаем каждый знак по отдельности, сравнивая его с искомым значением.
Разберем код реализации по шагам:
Функция КолБуквПосимвольно(ИсходнаяСтрока)
КоличествоБукв = 0;
ВсегоСимволов = СтрДлина(ИсходнаяСтрока);
Для Счетчик = 1 По ВсегоСимволов Цикл
ТекущийСимвол = Сред(ИсходнаяСтрока, Счетчик, 1);
Если ТекущийСимвол = "а" Тогда
КоличествоБукв = КоличествоБукв + 1;
КонецЕсли;
КонецЦикла;
Возврат КоличествоБукв;
КонецФункции
Важное примечание по производительности: Данный метод является самым медленным. При работе со строками длиной в сотни тысяч символов интерпретатор 1С будет тратить значительное время на выделение памяти под каждый извлеченный символ ТекущийСимвол на каждой итерации цикла.
Интересный альтернативный подход базируется на разделении строки на массив подстрок. В качестве разделителя мы указываем искомую букву «а». Платформа разрежет исходный текст во всех местах, где встречается данный символ, и вернет массив полученных фрагментов. Количество элементов в полученном массиве всегда будет на единицу больше, чем количество символов-разделителей.
Давайте посмотрим на программный код данного решения:
Функция КолБуквЧерезРазбиение(ИсходнаяСтрока)
МассивФрагментов = СтрРазделить(ИсходнаяСтрока, "а", Истина);
КоличествоВхождений = МассивФрагментов.Количество() - 1;
// Корректировка для пустой строки
Если КоличествоВхождений < 0 Тогда
Возврат 0;
КонецЕсли;
Возврат КоличествоВхождений;
КонецФункции
Обратите внимание на третий параметр функции СтрРазделить — флаг сохранения пустых строк. Мы передаем значение Истина, чтобы платформа корректно учитывала ситуации, когда искомые буквы стоят в самом начале, в самом конце или подряд друг за другом в строке.
Для решения сложных задач поиска по шаблону в операционной системе Windows можно задействовать возможности библиотеки VBScript. Это мощное решение, которое позволяет находить вхождения символов с использованием регулярных выражений. Мы создаем объект VBScript.RegExp, задаем шаблон поиска и получаем количество совпадений напрямую.
Проанализируем пример кода:
Функция КолБуквЧерезRegExp(ИсходнаяСтрока)
Попытка
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина; // Поиск без учета регистра
RegExp.Pattern = "а"; // Шаблон поиска - буква "а"
РезультатыПоиска = RegExp.Execute(ИсходнаяСтрока);
Возврат РезультатыПоиска.Count;
Исключение
// Резервный метод на случай выполнения на сервере Linux
Возврат КолБуквРазницаДлин(ИсходнаяСтрока);
КонецПопытки;
КонецФункции
Критически важное ограничение: Этот метод категорически не рекомендуется использовать в кроссплатформенных конфигурациях. COM-объекты создаются средствами операционной системы Windows. Если ваш сервер приложений 1С работает под управлением Linux, вызов Новый COMОбъект приведет к аварийному завершению работы процедуры. Всегда оборачивайте такие участки в блоки Попытка...Исключение. Для обхода таких ограничений можно использовать подсистему для нативной работы с регулярными выражениями.
Если вам все же необходимо реализовать перебор в коде, но вы хотите избежать медленного посимвольного вырезания через Сред(), можно использовать встроенную функцию СтрНайти. В современных версиях платформы 1С 8.3 эта функция поддерживает параметр стартовой позиции поиска, что позволяет быстро перемещаться от одного найденного символа к другому.
Рассмотрим пример реализации такого алгоритма:
Функция КолБуквЧерезСтрНайти(ИсходнаяСтрока)
Количество = 0;
ТекущаяПозиция = 1;
Пока Истина Цикл
ТекущаяПозиция = СтрНайти(ИсходнаяСтрока, "а", , ТекущаяПозиция);
Если ТекущаяПозиция = 0 Тогда
Прервать; // Символ больше не найден
КонецЕсли;
Количество = Количество + 1;
ТекущаяПозиция = ТекущаяПозиция + 1; // Сдвигаем поиск на следующий символ
КонецЦикла;
Возврат Количество;
КонецФункции
Этот способ работает значительно быстрее обычного посимвольного цикла, поскольку платформа пропускает «неинтересные» участки строки мгновенно.
При решении задач на подсчет символов в реальных базах данных (а не в учебных примерах) необходимо учитывать специфику работы платформы 1С и человеческий фактор.
В языке 1С стандартный оператор сравнения равенства = для строк по умолчанию является регистронезависимым. Это означает, что выражение "а" = "А" вернет результат Истина. Соответственно, при обычном сравнении в цикле вы посчитаете и маленькие, и большие буквы.
Если перед вами стоит задача посчитать строго строчные буквы «а», обычное равенство не подойдет. В этом случае нужно использовать функцию точного сравнения СтрСравнить (появилась в платформе 8.3.6) или анализировать коды символов:
// Пример точной проверки регистра
Если СтрСравнить(ТекущийСимвол, "а") = 0 Тогда
// Это именно маленькая буква "а"
КонецЕсли;
Очень часто пользователи при вводе данных в базу случайно или намеренно переключаются на английскую раскладку клавиатуры. Визуально русская буква «а» и английская «a» абсолютно идентичны на экране, но для компьютера это разные символы с разными цифровыми кодами (Unicode 1072 для кириллицы и Unicode 97 для латиницы).
В качественном промышленном коде перед подсчетом необходимо либо обрабатывать оба варианта символа, либо предварительно очищать / конвертировать строку. Давайте посмотрим, как учесть оба варианта:
// Считаем и русскую, и английскую буквы "а" через замену
СтрокаОчищенная = СтрЗаменить(ИсходнаяСтрока, "а", ""); // Кириллица
СтрокаОчищенная = СтрЗаменить(СтрокаОчищенная, "a", ""); // Латиница
Количество = СтрДлина(ИсходнаяСтрока) - СтрДлина(СтрокаОчищенная);
Если вам требуется посчитать количество букв в полях справочника или документа (например, найти все подозрительные наименования номенклатуры) по всей базе данных, то выгрузка каждого объекта в память сервера приложений займет слишком много времени.
Начиная с версии платформы 8.3.20 функции работы со строками, включая СтрЗаменить и СтрДлина, стали доступны прямо внутри языка запросов 1С. Это позволяет перенести всю вычислительную нагрузку на СУБД (MS SQL Server, PostgreSQL) и получить готовый результат моментально:
// Пример конструкции в запросе 1С
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
(ДЛИНА(Номенклатура.Наименование) - ДЛИНА(ПОДСТРОКА(ПОДМЕНИТЬ(Номенклатура.Наименование, "а", ""), 1, 1000))) КАК КолБуквА
ИЗ
Справочник.Номенклатура КАК Номенклатура
Мы проанализировали различные методы подсчета символов в строке без использования специализированной функции. Для большинства повседневных задач разработки в 1С наиболее предпочтительным является Решение 1 (разница длин строк через СтрЗаменить) благодаря его максимальному быстродействию и лаконичности кода. Если же перед вами стоит сложная задача с учетом регистра или специфических шаблонов, используйте комбинацию посимвольного перебора с функциями точного сравнения строк.