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

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

Как перебрать все символы в строке 1С

Способы перебора символов строки в 1С: цикл Для, функции СтрДлина, Сред, КодСимвола. Примеры кода, типичные ошибки и проверка результата.

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

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

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

Базовый перебор символов циклом Для

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

Процедура ПримерПеребора()

Строка = "Артикул-123";

ДлинаСтроки = СтрДлина(Строка);

Для Позиция = 1 По ДлинаСтроки Цикл

Символ = Сред(Строка, Позиция, 1);

Сообщить("Позиция " + Позиция + ": " + Символ);

КонецЦикла;

КонецПроцедуры

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

Если строка может быть пустой, отдельная проверка не обязательна: при СтрДлина(Строка) = 0 цикл просто не выполнится ни разу, и ошибки не возникнет. Это безопасное поведение упрощает код.

bsl
Для Позиция = 1 По СтрДлина(Строка) Цикл
    Символ = Сред(Строка, Позиция, 1);
КонецЦикла;

Анализ символа: коды, цифры, буквы

Чтобы принимать решения внутри цикла, символ сравнивают либо напрямую со строковым литералом, либо через его код Unicode функцией КодСимвола(). Прямое сравнение нагляднее, когда набор допустимых знаков невелик: Если Символ = "-" Или Символ = "/" Тогда.

Для проверки принадлежности к диапазонам удобнее коды. Цифры «0»–«9» имеют коды с 48 по 57, заглавные латинские буквы — с 65 по 90, строчные — с 97 по 122. Кириллица занимает диапазон с 1040 по 1103, кроме букв «Ё» (код 1025) и «ё» (код 1105), которые стоят отдельно — это частая ловушка при проверке русского текста.

Функция ЭтоЦифра(Символ)

Код = КодСимвола(Символ);

Возврат Код >= 48 И Код <= 57;

КонецФункции

Обратное преобразование выполняет функция Символ(Код) — она возвращает символ по его коду. Так можно, например, сформировать строку из управляющих символов: перевод строки имеет код 10, табуляция — 9. Впрочем, для типовых служебных символов удобнее использовать объект Символы.ПС, Символы.Таб и другие предопределённые значения.

Практический сценарий: очистка строки от лишних символов

Частая прикладная задача — оставить в строке только допустимые символы, например только цифры из номера телефона или документа. Перебор с накоплением результата решает её напрямую: допустимые символы дописываются в новую строку, остальные отбрасываются.

Функция ОставитьТолькоЦифры(ИсходнаяСтрока)

Результат = "";

Для Позиция = 1 По СтрДлина(ИсходнаяСтрока) Цикл

Символ = Сред(ИсходнаяСтрока, Позиция, 1);

Код = КодСимвола(Символ);

Если Код >= 48 И Код <= 57 Тогда

Результат = Результат + Символ;

КонецЕсли;

КонецЦикла;

Возврат Результат;

КонецФункции

Порядок действий при очистке строки
  1. 1
    Определите точный набор допустимых символов или их кодовые диапазоны
  2. 2
    Инициализируйте пустую строку-результат до цикла
  3. 3
    Пройдите циклом Для от 1 до СтрДлина по исходной строке
  4. 4
    Извлеките символ функцией Сред и проверьте его допустимость
  5. 5
    Допишите подходящий символ к результату
  6. 6
    Проверьте функцию на пустой строке, строке без допустимых символов и строке с «ё»

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

Подсчёт вхождений и поиск позиций символа

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

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

Функция ПозицииСимвола(Строка, ИскомыйСимвол)

Позиции = Новый Массив;

Для Позиция = 1 По СтрДлина(Строка) Цикл

Если Сред(Строка, Позиция, 1) = ИскомыйСимвол Тогда

Позиции.Добавить(Позиция);

КонецЕсли;

КонецЦикла;

Возврат Позиции;

КонецФункции

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

Сравнение вариантов перебора и поиска

Цикл Для + Сред

Универсальный способ: посимвольный анализ, фильтрация, сбор позиций. Медленнее встроенных функций на длинных строках.

СтрНайти

Поиск первого вхождения подстроки. Не подходит, когда нужны все позиции или анализ каждого символа.

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

Быстрый подсчёт вхождений подстроки. Не возвращает позиции и не позволяет анализировать контекст.

СтрЗаменить

Пакетная замена или удаление известных символов. Не работает с диапазонами и условиями.

Обратный перебор и посимвольное сравнение строк

Иногда строку нужно пройти справа налево — например, чтобы отбросить хвостовые пробелы вручную или найти последний разделитель. Для этого цикл строят с шагом -1:

Для Позиция = -СтрДлина(Строка) По -1 Цикл

Символ = Сред(Строка, -Позиция, 1);

КонецЦикла;

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

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

Типичные ошибки
01
Начало цикла с нуля вместо единицы — первый символ пропускается, а Сред(Строка, 0, 1) ведёт себя неочевидно
02
Сравнение результата СтрНайти без проверки на 0 — при отсутствии вхождения логика работает с несуществующей позицией
03
Забытая отдельная обработка букв «Ё» и «ё» при проверке кириллицы по диапазону кодов
04
Регистрозависимое сравнение символов там, где регистр не важен — используйте ВРег() или НРег() перед сравнением
05
Изменение перебираемой строки внутри цикла при кэшированной длине — часть символов пропускается или читается дважды

Производительность и ограничения

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

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

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

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

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

Функция обработки строки
Норма

Корректно работает на пустой строке, строке из одного символа и строке без допустимых знаков

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

Ошибка выполнения или неинициализированный результат на краевых случаях

Границы перебора
Норма

Обработаны первый и последний символы, цикл не выходит за длину строки

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

Первый символ пропущен или лишняя итерация за пределами строки

Кириллический текст
Норма

Строки с «Ё» и «ё» проходят проверки наравне с остальными буквами

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

Текст с «ё» ошибочно отклоняется

Контроль результата и отладка

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

В отладчике конфигуратора поставьте точку останова внутри цикла и наблюдайте переменные Позиция, Символ и накапливаемый результат. Если цикл длинный, используйте условную точку останова по номеру позиции, чтобы не проходить итерации вручную.

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

Итог

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

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

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

Можно ли перебрать символы строки циклом «Для Каждого» в 1С?

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

Что вернёт функция Сред(), если позиция больше длины строки?

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

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

Приведите оба значения к одному регистру перед сравнением: ВРег(Символ1) = ВРег(Символ2). Учтите, что операция создаёт новую строку, поэтому в длинных циклах выгоднее привести к нужному регистру всю исходную строку один раз до начала перебора.

Как узнать код символа и зачем это нужно?

Функция КодСимвола(Символ) возвращает числовой код Unicode. Она нужна для проверки принадлежности символа диапазону (цифры, латиница, кириллица), когда перечислять все допустимые литералы неудобно. Обратное преобразование выполняет функция Символ(Код).

Что быстрее: посимвольный цикл или СтрЗаменить()?

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

Почему перебор «ломает» эмодзи и редкие иероглифы?

Такие знаки кодируются суррогатными парами и занимают две позиции в строке. Функция Сред() извлекает каждую половину отдельно, и символ разрушается. Для типовых учётных строк это не проблема, но при обработке произвольного текста от пользователей учитывайте эту особенность и по возможности избегайте посимвольного разбиения непроверенных данных.