К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как найти подстроку в строке в 1С

Как найти подстроку в строке в 1С: функции СтрНайти, Найти и СтрНайтиИПодсветить, учёт регистра, поиск с конца, примеры кода и типичные ошибки при работе со строками.

Поиск подстроки — одна из самых частых задач при разработке на встроенном языке 1С: разбор наименований, проверка введённых пользователем данных, анализ текста ошибок, фильтрация файлов по расширению. В зависимости от версии платформы и задачи используются разные функции: устаревшая Найти(), современная СтрНайти() или регулярные выражения через внешние компоненты.

Ключевой момент, который нужно понять сразу: функции поиска подстроки возвращают не булево «найдено/не найдено», а номер позиции первого символа найденной подстроки. Если подстрока не найдена, возвращается 0. Нумерация символов в строке начинается с 1, а не с 0 — это частая причина ошибок у разработчиков, пришедших из других языков.

Ниже разобраны синтаксис основных функций, учёт регистра, поиск нескольких вхождений, проверка результата и типичные ошибки, которые приводят к неверной логике обработки данных.

Базовый поиск подстроки функцией СтрНайти

Функция СтрНайти() появилась в платформе 8.3.6 и стала стандартным способом поиска подстроки. Её полный синтаксис:

СтрНайти(Строка, ПодстрокаПоиска, НаправлениеПоиска, НачальнаяПозиция, НомерВхождения)

Обязательны только первые два параметра: исходная строка и искомая подстрока. Остальные параметры управляют направлением поиска, стартовой позицией и номером вхождения. Простейший пример:

Наименование = "Бумага А4 офисная 80 г/м2";

Если СтрНайти(Наименование, "А4") > 0 Тогда

Сообщить("Это бумага формата А4");

КонецЕсли;

Функция возвращает позицию первого символа найденной подстроки. Для строки «Бумага А4 офисная» вызов СтрНайти(Наименование, "А4") вернёт 8, потому что «А» — восьмой символ строки. Если подстроки в строке нет, результат равен 0.

Функция Найти в старом коде

В конфигурациях, написанных до платформы 8.3.6, вместо СтрНайти() используется глобальная функция Найти() с более простым синтаксисом:

Позиция = Найти(Строка, Подстрока);

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

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

СтрНайти или Найти

СтрНайти()

Современный стандарт с платформы 8.3.6. Поддерживает направление поиска, начальную позицию и номер вхождения. Использовать во всём новом коде.

Найти()

Устаревшая функция, только поиск первого вхождения с начала строки. Оставлять в старом коде, менять при доработках.

Регулярные выражения

Через VBScript.RegExp на Windows или внешние компоненты. Нужны только для сложных шаблонов, для простой подстроки избыточны.

Поиск с учётом и без учёта регистра

Встроенные функции поиска в 1С чувствительны к регистру: СтрНайти("Бумага А4", "а4") вернёт 0, потому что «а4» и «А4» — разные последовательности символов. Это одна из самых частых причин «неработающего» поиска.

Стандартный приём для поиска без учёта регистра — привести обе строки к одному регистру функциями ВРег() (верхний регистр) или НРег() (нижний регистр):

Если СтрНайти(НРег(Наименование), НРег(ПользовательскийВвод)) > 0 Тогда

// совпадение найдено независимо от регистра

КонецЕсли;

Учтите ограничение: НРег() и ВРег() корректно обрабатывают буквы, но не меняют цифры и спецсимволы — для задачи поиска это обычно не важно. А вот похожие по начертанию символы разных алфавитов (кириллическая «а» и латинская «a») регистром не свести: такие символы придётся нормализовать заменой через СтрЗаменить(), если данные приходят из внешних источников.

Поиск с конца строки и несколько вхождений

Третий параметр СтрНайти() — направление поиска из системного перечисления НаправлениеПоиска: СНачала (по умолчанию) или СКонца. Поиск с конца удобен, когда нужно последнее вхождение, например позиция последней точки в имени файла для выделения расширения:

ИмяФайла = "отчет.продажи.xlsx";

ПозицияТочки = СтрНайти(ИмяФайла, ".", НаправлениеПоиска.СКонца);

Если ПозицияТочки > 0 Тогда

Расширение = Сред(ИмяФайла, ПозицияТочки + 1); // "xlsx"

КонецЕсли;

Четвёртый параметр — начальная позиция, с которой начинается поиск. Пятый — номер вхождения: 1 — первое, 2 — второе и так далее. Так можно найти второе вхождение без ручной обрезки строки:

Строка = "Иванов;Петров;Сидоров";

ВтораяТочкаСЗапятой = СтрНайти(Строка, ";", , , 2); // позиция второго ";"

Если вхождений меньше, чем запрошенный номер, функция вернёт 0. Это удобно использовать в цикле для перебора всех вхождений: увеличивайте номер вхождения, пока результат не станет равен нулю.

bsl
НомерВхождения = 1;
Пока Истина Цикл
    Позиция = СтрНайти(Текст, ";", , , НомерВхождения);
    Если Позиция = 0 Тогда
        Прервать;
    КонецЕсли;
    Сообщить("Вхождение " + НомерВхождения + " на позиции " + Позиция);
    НомерВхождения = НомерВхождения + 1;
КонецЦикла;

Проверка результата и обработка ошибок

Корректная проверка результата поиска — сравнение с нулём: Если Позиция > 0 Тогда или Если Позиция <> 0 Тогда. Не используйте конструкцию Если СтрНайти(...) Тогда без сравнения: в языке 1С число не преобразуется в булево автоматически, и такой код вызовет ошибку исполнения.

Отдельно проверяйте граничные случаи. Если исходная строка пустая, поиск всегда вернёт 0. Если искомая подстрока пустая, поведение зависит от платформы и может вернуть начальную позицию — не полагайтесь на это, а проверяйте входные данные явно через ПустаяСтрока() до поиска.

При работе с данными, введёнными пользователем или загруженными из файлов, полезно предварительно обрезать пробелы функцией СокрЛП(): лишний пробел в начале или конце искомой строки — типичная причина того, что заведомо существующая подстрока «не находится».

Контрольные точки

Как проверить результат

Значение, возвращённое СтрНайти
Норма

Число от 1 до длины строки — подстрока найдена

Тревожный признак

0 — подстрока не найдена или входные данные пустые

Поиск должен находить заведомо существующий текст
Норма

Позиция совпадает с ожидаемой при ручной проверке

Тревожный признак

Возвращается 0 — проверьте регистр, пробелы и похожие символы разных алфавитов

Выделенная подстрока через Сред(Строка, Позиция, Длина)
Норма

Совпадает с искомой подстрокой

Тревожный признак

Смещение на символ — проверьте, что нумерация велась с 1

Типичные ошибки при поиске подстроки

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

Вторая группа — игнорирование регистра и пробелов. Поиск «не работает», хотя подстрока визуально присутствует: виноваты разный регистр букв, неразрывные пробелы из скопированного текста или кириллические буквы вместо латинских. Диагностируется это выводом кодов символов через КодСимвола() в подозрительной позиции.

Третья группа — использование поиска подстроки там, где нужны более строгие проверки. Например, проверка валюты документа по вхождению «USD» в строку найдёт и «USDT», и «NOTUSD». Для точных сравнений используйте равенство строк, для шаблонов — оператор ПОДОБНО в запросах, а не СтрНайти().

Типичные ошибки
01
Проверка результата через Если СтрНайти(...) Тогда без сравнения с нулём — ошибка исполнения, число не преобразуется в булево
02
Поиск без приведения регистра, когда регистр входных данных не гарантирован — ложные промахи
03
Ожидание нумерации символов с 0 — смещение позиций при выделении подстроки через Сред()
04
Поиск по необрезанной строке — ведущие и конечные пробелы ломают сравнение
05
Использование СтрНайти для точного сравнения строк вместо оператора равенства

Поиск подстроки в запросах: оператор ПОДОБНО

Когда нужно отобрать записи в базе по вхождению подстроки — например, все товары, в наименовании которых есть слово «кабель», — используйте не перебор с СтрНайти(), а запрос с оператором ПОДОБНО. Это на порядки быстрее, потому что фильтрация выполняется на стороне СУБД:

Запрос.Текст =

"ВЫБРАТЬ Номенклатура.Ссылка

|ИЗ Справочник.Номенклатура КАК Номенклатура

|ГДЕ Номенклатура.Наименование ПОДОБНО &Шаблон";

Запрос.УстановитьПараметр("Шаблон", "%кабель%");

Символ % означает любую последовательность символов любой длины, _ — ровно один произвольный символ. Шаблон "%кабель%" находит вхождение в любом месте строки, "кабель%" — только в начале. Учтите, что специальные символы шаблона в искомом тексте нужно экранировать, иначе поиск даст неверный результат.

Производительный нюанс: шаблон, начинающийся с %, не позволяет СУБД использовать индекс по полю, поэтому на больших таблицах такой отбор выполняется полным сканированием. Для редких операций это приемлемо, но в массовых обработках и отчётах по крупным справочникам закладывайте время выполнения и по возможности сужайте выборку другими условиями.

Маршрут решения

Как выбрать способ поиска

Нужно проверить вхождение текста в переменную в кодеИспользуйте СтрНайти() с проверкой результата > 0
Регистр входных данных не гарантированПриведите обе строки к одному регистру через НРег() перед поиском
Нужно отобрать записи в базе по вхождению текстаИспользуйте запрос с ПОДОБНО и параметром-шаблоном
Нужно последнее вхождение, например расширение файлаСтрНайти с параметром НаправлениеПоиска.СКонца
Нужен поиск по сложному шаблону с вариациямиРассмотрите регулярные выражения; СтрНайти для этого не подходит

Частые вопросы

Что возвращает СтрНайти, если подстрока не найдена?

Функция возвращает число 0. Поэтому проверка результата всегда строится как сравнение с нулём: Если СтрНайти(Строка, Подстрока) > 0 Тогда ... КонецЕсли. Отрицательных значений функция не возвращает.

Как проверить, что строка начинается с определённой подстроки?

Используйте функцию СтрНачинаетсяС(Строка, Подстрока) — она возвращает булево Истина или Ложь и читается нагляднее, чем сравнение позиции с единицей. Для конца строки есть парная функция СтрЗаканчиваетсяНа.

Почему СтрНайти не находит текст, который точно есть в строке?

Чаще всего причины три: разный регистр букв (поиск регистрозависим), лишние или неразрывные пробелы, визуально похожие символы разных алфавитов — кириллическая «а» вместо латинской. Приведите строки к одному регистру, обрежьте пробелы через СокрЛП и при необходимости проверьте коды символов функцией КодСимвола.

Как найти все вхождения подстроки, а не только первое?

Передайте в СтрНайти пятый параметр — номер вхождения — и перебирайте его в цикле от 1, пока функция не вернёт 0. Альтернатива для разбора строки по разделителю — функция СтрРазделить, которая сразу возвращает массив частей.

Чем заменить СтрНайти для поиска по шаблону с вариациями?

Для отбора данных в базе — оператор ПОДОБНО в запросе с символами % и _. Для сложных шаблонов в коде — регулярные выражения через объект VBScript.RegExp (только Windows) или внешние компоненты. Для простой фиксированной подстроки регулярные выражения избыточны.

Итог

Что важно запомнить

СтрНайти(Строка, Подстрока) возвращает позицию первого вхождения с нумерацией от 1 или 0, если подстрока не найдена. Поиск регистрозависим — при необходимости приводите строки к одному регистру. Для отбора данных в базе используйте ПОДОБНО в запросе, а результат поиска всегда проверяйте сравнением с нулём.