Разработка и Конфигурация · 12 мин
Как найти часть строки в 1С
Как найти часть строки в 1С: функции СтрНайти, Найти, СтрЧислоВхождений, поиск с учётом регистра, примеры кода, типичные ошибки и ответы на вопросы.
Поиск подстроки — одна из самых частых задач при разработке на встроенном языке 1С: проверка, содержит ли наименование нужное слово, разбор номенклатурного номера, поиск фрагмента в адресе или комментарии. Во встроенном языке для этого есть несколько функций, и у каждой свои особенности: направление поиска, учёт регистра, возвращаемое значение.
Основной инструмент современных конфигураций — функция СтрНайти(), появившаяся в платформе 8.3.6 вместе со «строчными» функциями. В старом коде встречается устаревшая Найти(), которая работает иначе и часто становится источником ошибок при доработке типовых решений. Важно понимать разницу между ними, чтобы не получить неожиданный результат.
Ниже разобраны основные способы поиска части строки: позиция вхождения, проверка факта вхождения, подсчёт количества вхождений, поиск без учёта регистра и извлечение найденного фрагмента. Все примеры применимы как в толстом, так и в тонком клиенте, на сервере и в модулях форм.
Функция СтрНайти: базовый синтаксис и параметры
Функция СтрНайти() имеет следующий синтаксис: СтрНайти(Строка, ПодстрокаПоиска, НаправлениеПоиска, НачальнаяПозиция, НомерВхождения). Обязательны только первые два параметра, остальные позволяют тонко управлять поиском.
Результат — число: позиция символа, с которого начинается вхождение (нумерация с единицы), либо 0, если подстрока не найдена. Пустая искомая подстрока считается найденной и возвращает начальную позицию поиска — это важно учитывать при проверках.
Строка = "Заказ покупателя №000123 от поставщика";
Позиция = СтрНайти(Строка, "№000123");
// Позиция = 17
Если СтрНайти(Строка, "поставщик") > 0 Тогда
Сообщить("Подстрока найдена");
КонецЕсли;
Параметр НачальнаяПозиция задаёт, с какого символа начинать поиск, а НомерВхождения — какое по счёту вхождение вернуть. Это удобно, когда нужно найти второе или третье вхождение разделителя, например второй пробел в ФИО.
Поиск с конца строки и поиск нескольких вхождений
Третий параметр — НаправлениеПоиска — принимает значения НаправлениеПоиска.СНачала (по умолчанию) или НаправлениеПоиска.СКонца. Поиск с конца полезен, когда нужно найти последний разделитель: например, последний слэш в пути к файлу, чтобы отделить имя файла от каталога.
Путь = "C:\Документы\Отчеты\Продажи.xlsx";
Позиция = СтрНайти(Путь, "\", НаправлениеПоиска.СКонца);
ИмяФайла = Сред(Путь, Позиция + 1);
// ИмяФайла = "Продажи.xlsx"
Для перебора всех вхождений подстроки используют цикл с параметром НачальнаяПозиция: каждая следующая итерация начинается с позиции после найденного вхождения. Альтернатива — функция СтрЧислоВхождений(), которая сразу возвращает количество вхождений без указания позиций.
Строка = "яблоко;груша;яблоко;слива;яблоко";
Количество = СтрЧислоВхождений(Строка, "яблоко");
// Количество = 3
Учёт регистра: почему поиск «не находит» очевидное
И СтрНайти(), и устаревшая Найти() по умолчанию чувствительны к регистру: «Заказ» и «заказ» — разные подстроки. Это самая частая причина жалоб на «неработающий» поиск. Если регистр не важен, приведите обе строки к одному регистру перед поиском.
Наименование = "Кабель ВВГнг 3х2.5";
Если СтрНайти(НРег(Наименование), НРег("ввгнг")) > 0 Тогда
// вхождение найдено независимо от регистра
КонецЕсли;
Учтите, что НРег() и ВРег() преобразуют только буквы, поэтому такой приём безопасен для цифр и спецсимволов. Однако не используйте результат преобразования для вывода пользователю — только для сравнения, иначе потеряете исходное написание.
Устаревшая функция Найти и отличия от СтрНайти
В конфигурациях, написанных до платформы 8.3.6, повсеместно используется Найти(ПодстрокаПоиска, Строка). Обратите внимание на порядок аргументов — он обратный по сравнению со СтрНайти(). Это главный подводный камень при рефакторинге: механическая замена имени функции без перестановки параметров приводит к тому, что поиск всегда возвращает 0.
Функция Найти() не поддерживает направление поиска, начальную позицию и номер вхождения — она всегда ищет первое вхождение с начала строки. Если в старом коде требуется поиск с конца, придётся либо переходить на СтрНайти(), либо реализовывать цикл вручную.
// Старый вариант
Позиция = Найти("Привет, мир", "мир"); // 9
// Эквивалент на современном синтаксисе
Позиция = СтрНайти("Привет, мир", "мир"); // 9
СтрНайти или Найти
Рекомендуемый вариант: поддерживает направление поиска, начальную позицию и номер вхождения. Используйте во всём новом коде
Устаревшая функция, оставлена для совместимости. Только первое вхождение с начала строки, обратный порядок параметров. Не применяйте в новых разработках
Когда нужно только количество вхождений без позиций — например, проверить, что разделитель встречается ровно один раз
Извлечение найденной части строки
Найти позицию — половина задачи: обычно дальше нужно вырезать фрагмент. Для этого служат Лев(), Прав() и Сред(). Типичный сценарий — взять всё до разделителя или после него.
Строка = "Артикул: АБВ-12345";
Позиция = СтрНайти(Строка, ":");
Если Позиция > 0 Тогда
Значение = СокрЛП(Сред(Строка, Позиция + 1));
// Значение = "АБВ-12345"
КонецЕсли;
Обязательно проверяйте, что вхождение найдено, прежде чем вызывать Сред(). Если позиция равна 0, вы получите либо всю строку, либо некорректный фрагмент — в зависимости от арифметики смещения. Такая ошибка не вызывает исключения и потому долго остаётся незамеченной.
Если строка содержит несколько однотипных частей, разделённых одинаковым символом (CSV-строки, составные номера), удобнее не искать вхождения по одному, а разложить строку функцией СтрРазделить() в массив и работать с элементами по индексам.
- 1Определите разделитель или искомый фрагмент и проверьте, может ли его не быть в строке
- 2Выполните поиск: Позиция = СтрНайти(Строка, Разделитель)
- 3Проверьте результат: Если Позиция > 0 Тогда — иначе предусмотрите ветку для строки без разделителя
- 4Извлеките нужную часть через Лев(), Сред() или Прав() и обрежьте пробелы функцией СокрЛП()
- 5Проверьте результат на тестовых строках: с фрагментом в начале, в середине, в конце и без фрагмента
Альтернативы: СтрШаблон, регулярные выражения и поиск в запросах
Когда искомый шаблон сложнее простой подстроки (например, «цифры между дефисами»), встроенных строковых функций недостаточно. В толстом клиенте и на сервере Windows доступен COM-объект VBScript.RegExp для регулярных выражений, но он не работает в веб-клиенте и на Linux-сервере — учитывайте это при проектировании.
Если поиск части строки нужен для отбора данных, не выгружайте записи и не перебирайте их в цикле — используйте оператор ПОДОБНО в запросе: ГДЕ Наименование ПОДОБНО "%кабель%". Это выполняется на стороне СУБД и на больших таблицах работает на порядки быстрее программного перебора.
В динамических списках и формах выбора поиск по подстроке уже встроен в платформу: пользователь вводит текст, и список фильтруется автоматически. Программно это поведение настраивается через свойства поля ввода «Способ поиска строки» и «Поиск при вводе», без написания собственных функций поиска.
Проверка результата и отладка
Надёжный способ убедиться, что поиск работает, — проверить его на четырёх граничных случаях: подстрока в начале строки, в середине, в конце и полное отсутствие подстроки. Также проверьте строку, где искомый фрагмент встречается несколько раз, если используете номер вхождения или поиск с конца.
Для отладки используйте конфигуратор: точка останова перед строкой поиска и просмотр значений Строка и Позиция в табло. Часто оказывается, что в строке есть неразрывные пробелы или невидимые символы из скопированного текста — тогда визуально совпадающая подстрока не находится. Очистить строку от лишних пробелов помогает СокрЛП(), а от неразрывных пробелов — СтрЗаменить(Строка, Символ(160), " ").
Как проверить результат
Число от 1 до длины строки при найденной подстроке, 0 при отсутствии
Позиция 0 при визуально присутствующем фрагменте — вероятны различия в регистре или невидимые символы
Фрагмент совпадает с ожидаемым, без лишних пробелов по краям
Лишний первый символ или обрезанный конец — ошибка в арифметике смещения Сред()
Выполняется отдельная ветка кода, исключений нет
Сред() вызывается при позиции 0 и возвращает некорректные данные молча
При массовой обработке данных (например, разборе тысяч строк из файла) измеряйте время выполнения: вложенные циклы поиска по длинным строкам могут стать узким местом. В таких случаях выносите инвариантные вычисления из цикла и по возможности заменяйте программный перебор запросом.
Что важно запомнить
Используйте СтрНайти(Строка, Подстрока) — функция возвращает позицию вхождения или 0. Проверяйте результат явным сравнением с нулём перед извлечением фрагмента. Для поиска без учёта регистра приводите обе строки через НРег(). Устаревшую Найти() не применяйте в новом коде, а при её замене помните про обратный порядок параметров. Для отбора данных по части строки используйте ПОДОБНО в запросе вместо программного перебора.
Частые вопросы
Что возвращает СтрНайти, если подстрока не найдена?
Функция возвращает число 0. Поэтому проверка наличия вхождения записывается как «Если СтрНайти(Строка, Подстрока) > 0 Тогда». Полагаться на неявное приведение числа к булеву не стоит — явное сравнение читается однозначно и защищает от ошибок при доработке кода.
Как найти часть строки без учёта регистра?
Приведите обе строки к одному регистру перед поиском: СтрНайти(НРег(Строка), НРег(Подстрока)). Подойдёт и ВРег() — важно лишь применить одну и ту же функцию к обоим аргументам. Преобразование не затрагивает цифры и спецсимволы, поэтому способ безопасен для смешанных строк.
Чем отличаются СтрНайти и Найти?
Главное отличие — порядок параметров: Найти(Подстрока, Строка) против СтрНайти(Строка, Подстрока). Кроме того, СтрНайти поддерживает направление поиска, начальную позицию и номер вхождения, а Найти всегда ищет первое вхождение с начала. Найти считается устаревшей и сохраняется только для совместимости со старым кодом.
Как найти последнее вхождение подстроки?
Передайте третьим параметром НаправлениеПоиска.СКонца: СтрНайти(Строка, Подстрока, НаправлениеПоиска.СКонца). Функция вернёт позицию последнего вхождения. Это стандартный приём для отделения имени файла от пути или расширения от имени.
Как проверить, что строка начинается с определённого фрагмента?
Сравните результат СтрНайти с единицей: Если СтрНайти(Строка, "Префикс") = 1 Тогда — строка начинается с указанного фрагмента. Альтернатива — сравнение Лев(Строка, СтрДлина("Префикс")) с самим фрагментом, что иногда читается нагляднее.
Как найти подстроку в таблице значений или справочнике?
Перебор строк с СтрНайти подходит только для небольших объёмов. Для отбора по базе данных используйте запрос с оператором ПОДОБНО и шаблоном "%фрагмент%" — он выполняется на стороне СУБД. Для уже загруженной таблицы значений можно использовать метод НайтиСтроки с предварительно вычисленной колонкой или отбор через построитель, но простой цикл со СтрНайти тоже допустим при умеренном числе строк.