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

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

Как найти определённый символ в строке в 1С

Как найти определённый символ в строке 1С: функции СтрНайти, Найти, СтрЧислоВхождений, поиск с учётом регистра и типичные ошибки при работе со строками.

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

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

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

Какую функцию выбрать для поиска символа

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

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

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

Сравнение функций поиска

СтрНайти()

Универсальный вариант: направление поиска, номер вхождения, начальная позиция. Рекомендуется для нового кода.

Найти()

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

СтрЧислоВхождений()

Когда нужно не место символа, а количество его появлений в строке.

СтрНачинаетсяС() / СтрЗаканчиваетсяНа()

Когда важно только, стоит ли символ в начале или в конце строки.

Базовый поиск символа через СтрНайти

Простейший сценарий — узнать, есть ли символ в строке, и если есть, то где он стоит. Функция возвращает целое число: позицию первого символа найденной подстроки. Нумерация символов в строке начинается с 1, а не с 0, как в некоторых других языках программирования.

Строка = "Артикул:Т-145/Б";

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

// Позиция = 9

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

Сообщить("Символ найден на позиции " + Позиция);

Иначе

Сообщить("Символ не найден");

КонецЕсли;

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

Обратите внимание: поиск ведётся с учётом регистра. Строка «Артикул» и искомый символ «а» не совпадут с символом «А». Если регистр не важен, предварительно приведите обе строки к одному регистру функциями ВРег() или НРег().

bsl
Позиция = СтрНайти(НРег(Наименование), НРег(СимволПоиска));

Поиск второго и последующих вхождений

Часто первого вхождения недостаточно: например, в строке «Иванов;Иван;Иванович» нужно найти второй разделитель, чтобы отделить фамилию от имени. Для этого у СтрНайти() есть третий и четвёртый параметры — направление поиска и начальная позиция, а пятый параметр задаёт номер вхождения.

Строка = "Иванов;Иван;Иванович";

// Второе вхождение точки с запятой

Позиция2 = СтрНайти(Строка, ";", НаправлениеПоиска.СНачала, 1, 2);

// Позиция2 = 13

Альтернативный приём — искать следующее вхождение, начиная с позиции после предыдущего найденного символа. Для этого в качестве начальной позиции передаётся ПредыдущаяПозиция + 1. Такой подход удобен в циклах, когда количество вхождений заранее неизвестно.

Позиция = 0;

Пока Истина Цикл

Позиция = СтрНайти(Строка, ";", НаправлениеПоиска.СНачала, Позиция + 1);

Если Позиция = 0 Тогда

Прервать;

КонецЕсли;

// обработка найденной позиции

КонецЦикла;

Порядок поиска всех вхождений символа
  1. 1
    Инициализируйте переменную позиции нулём
  2. 2
    В цикле вызывайте СтрНайти с начальной позицией Позиция + 1
  3. 3
    Проверяйте результат: если 0 — вхождений больше нет, выходите из цикла
  4. 4
    Обрабатывайте найденную позицию внутри цикла

Поиск с конца строки

Задача найти последнее вхождение символа типична при разборе путей к файлам (последний слэш перед именем файла) или расширений (последняя точка). Для этого параметр направления поиска устанавливается в НаправлениеПоиска.СКонца.

Путь = "C:\Документы\Отчеты\Отчет.pdf";

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

Расширение = Сред(Путь, ПозицияТочки + 1);

// Расширение = "pdf"

Тот же приём работает для извлечения имени файла: найдите последний символ «\» или «/» и возьмите часть строки после него через Сред(). Если такой символ может отсутствовать, обязательно проверяйте результат на ноль — иначе при отсутствии разделителя вы получите некорректное значение.

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

Как проверить сам факт наличия символа

Если позиция не нужна, а требуется только ответ «символ есть или нет», достаточно сравнить результат СтрНайти() с нулём. Это стандартная проверка, например, при валидации email или запрете служебных символов в наименовании.

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

ВызватьИсключение "В наименовании недопустимый символ";

КонецЕсли;

Для подсчёта количества вхождений используйте СтрЧислоВхождений(Строка, Символ). Это удобно при проверке структуры строки: например, в корректном ИНН юридического лица не должно быть букв, а в разбираемой CSV-строке количество разделителей должно соответствовать ожидаемому числу колонок минус один.

Поиск специальных и невидимых символов

Отдельная категория задач — поиск символов, которые нельзя набрать в строковом литерале напрямую: перевод строки, табуляция, неразрывный пробел. Для этого используется объект Символы, доступный в глобальном контексте.

ПозицияПС = СтрНайти(Текст, Символы.ПС);      // перевод строки

ПозицияТаб = СтрНайти(Текст, Символы.Таб); // табуляция

ПозицияНПП = СтрНайти(Текст, Символ(160)); // неразрывный пробел

Неразрывный пробел (код 160) — частый источник ошибок при обмене данными: визуально он неотличим от обычного пробела, но сравнение строк даёт ложь, а поиск обычного пробела его не находит. Если строка пришла из Excel, веб-формы или скопирована из документа, имеет смысл предварительно заменить неразрывные пробелы обычными через СтрЗаменить(Строка, Символ(160), " ").

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

Типичные ошибки и отладка

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

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

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

Практический пример: разбор строки по разделителю

Закрепим материал на типовой задаче: есть строка вида «Код|Наименование|Цена», нужно извлечь все три части. Хотя для этого удобнее СтрРазделить(), вариант через СтрНайти() показывает реальное применение позиций.

Строка = "Т-145|Болт М8х30|12.50";

П1 = СтрНайти(Строка, "|");

П2 = СтрНайти(Строка, "|", НаправлениеПоиска.СНачала, П1 + 1);

Если П1 > 0 И П2 > 0 Тогда

Код = Лев(Строка, П1 - 1);

Наименование = Сред(Строка, П1 + 1, П2 - П1 - 1);

Цена = Сред(Строка, П2 + 1);

КонецЕсли;

Обратите внимание на вычисление длины средней части: П2 - П1 - 1. Здесь легко ошибиться на единицу, поэтому после написания такого кода проверьте его на контрольном примере с известным результатом. Если разделителей может быть произвольное количество, предпочтительнее СтрРазделить(Строка, "|"), возвращающая массив частей.

Итог

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

Используйте СтрНайти() для поиска символа: результат 0 означает «не найдено», нумерация позиций начинается с 1. Поиск чувствителен к регистру, спецсимволы задавайте через Символы или Символ(код), а для разбора строки по разделителю удобнее СтрРазделить().

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

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

Функция возвращает число 0. Это единственный надёжный признак отсутствия символа, поэтому перед использованием позиции всегда выполняйте проверку «Результат > 0».

Чем СтрНайти отличается от Найти?

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

Как найти символ без учёта регистра?

Приведите обе строки к одному регистру перед поиском: СтрНайти(ВРег(Строка), ВРег(Символ)). Помните, что возвращённая позиция останется корректной, так как смена регистра не меняет длину строки.

Как найти последнее вхождение символа?

Вызовите СтрНайти с параметром направления НаправлениеПоиска.СКонца: СтрНайти(Строка, ".", НаправлениеПоиска.СКонца). Это стандартный способ найти, например, точку перед расширением файла.

Как посчитать, сколько раз символ встречается в строке?

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

Почему поиск не находит пробел, который виден в строке?

Скорее всего, в строке стоит неразрывный пробел (код 160) или табуляция. Проверьте код символа функцией КодСимвола() и при необходимости замените такие символы через СтрЗаменить перед поиском.