Разработка и Конфигурация · 11 мин
Как заменить символы в строке в запросе 1С
Как заменить символы в строке в запросе 1С: функция СТРЗАМЕНИТЬ, примеры синтаксиса, обходные пути для старых платформ, типичные ошибки и проверка результата.
Задача замены символов в строке прямо в запросе возникает часто: нужно убрать пробелы из артикула, заменить дефисы в номере документа, нормализовать телефонный номер для сравнения или очистить наименование от служебных символов. В языке запросов 1С для этого предусмотрена функция СТРЗАМЕНИТЬ, но она доступна не во всех версиях платформы, поэтому важно понимать и обходные пути.
Главное ограничение языка запросов — отсутствие циклов и регулярных выражений. Замена выполняется только «в лоб»: указывается исходная строка, искомая подстрока и подстрока замены. Если нужно убрать несколько разных символов, приходится вкладывать вызовы функции друг в друга, что быстро делает текст запроса громоздким.
Ниже разобран синтаксис функции, практические примеры, способы работы на старых платформах без СТРЗАМЕНИТЬ, а также типичные ошибки, из-за которых запрос возвращает пустой результат или падает с ошибкой.
Функция СТРЗАМЕНИТЬ: синтаксис и требования к версии
Функция СТРЗАМЕНИТЬ появилась в языке запросов начиная с платформы 8.3.6. Если конфигурация работает на более ранней версии, запрос с этой функцией не пройдёт проверку и выдаст ошибку «Функция не найдена». Перед использованием проверьте версию платформы, на которой реально эксплуатируется база, а не только ту, что установлена у разработчика.
Синтаксис функции:
СТРЗАМЕНИТЬ(ИсходнаяСтрока, ПодстрокаПоиска, ПодстрокаЗамены)
Все три параметра обязательны и должны иметь строковый тип. Функция заменяет все вхождения искомой подстроки, а не только первое. Если подстрока поиска не найдена, возвращается исходная строка без изменений — это удобно, так как не требует предварительной проверки.
Пример простого запроса, убирающего пробелы из артикула:
ВЫБРАТЬ
СТРЗАМЕНИТЬ(Номенклатура.Артикул, " ", "") КАК АртикулБезПробелов
ИЗ
Справочник.Номенклатура КАК Номенклатура
Типовые примеры: пробелы, дефисы, скобки
Удаление символа
Чтобы удалить символ, в третьем параметре передаётся пустая строка. Так обрабатывают телефоны, ИНН, артикулы:
СТРЗАМЕНИТЬ(Контрагенты.Телефон, "-", "") КАК ТелефонБезДефисов
Замена одного символа на другой
Классический случай — замена десятичного разделителя или разделителя в номере:
СТРЗАМЕНИТЬ(Документ.НомерВходящего, "/", "-") КАК НомерДляПечати
Несколько замен через вложенные вызовы
Один вызов заменяет одну подстроку. Чтобы убрать из телефона скобки, пробелы и дефисы, вызовы вкладываются друг в друга:
СТРЗАМЕНИТЬ(
СТРЗАМЕНИТЬ(
СТРЗАМЕНИТЬ(Контрагенты.Телефон, "(", ""),
")", ""),
" ", "") КАК ТелефонОчищенный
Вложенность выполняется изнутри наружу: сначала убираются открывающие скобки, затем закрывающие, затем пробелы. При трёх-четырёх уровнях запрос ещё читаем; если символов больше, разумнее перенести обработку в код.
ВЫБРАТЬ
СТРЗАМЕНИТЬ(Номенклатура.Наименование, " ", " ") КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НЕ Номенклатура.ПометкаУдаленияЗамена символов в условии ГДЕ и при соединении
Функцию можно использовать не только в списке выборки, но и в условиях отбора — это частый приём при поиске дублей по «грязным» данным:
ВЫБРАТЬ
Контрагенты.Ссылка
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
СТРЗАМЕНИТЬ(Контрагенты.Наименование, " ", "") = &НормализованноеИмя
Так же функция применяется в условии соединения таблиц, когда ключи в двух источниках записаны в разном формате. Однако здесь есть важное ограничение: замена в условии отбора или соединения отключает использование индексов по этому полю. На больших таблицах (сотни тысяч записей) такой запрос будет сканировать таблицу целиком и выполняться заметно дольше.
Что делать на платформе ниже 8.3.6
Если СТРЗАМЕНИТЬ недоступна, есть два рабочих подхода.
Первый — собрать строку из частей функцией ПОДСТРОКА с конкатенацией. Способ громоздкий и годится только когда позиция заменяемого символа известна заранее, например при форматировании фиксированной длины:
ВЫБРАТЬ
ПОДСТРОКА(Документ.Номер, 1, 3) + "-" + ПОДСТРОКА(Документ.Номер, 4, 10) КАК НомерСДефисом
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
Второй, более универсальный путь — выполнить запрос без замены, а затем обработать результат во встроенном языке функцией СтрЗаменить() при обходе выборки или в цикле по таблице значений:
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
АртикулЧистый = СтрЗаменить(Выборка.Артикул, " ", "");
КонецЦикла;
Для массовой обработки удобно выгрузить результат в таблицу значений, добавить колонку и заполнить её в цикле — так исходные данные запроса остаются нетронутыми.
Сравнение вариантов
Подходит для платформы 8.3.6 и новее; обработка на стороне СУБД, удобно для отбора и соединения. Ограничение — одна подстрока за вызов и потеря индексов в условиях.
Работает на любой версии платформы, позволяет сложную логику и регулярные выражения через дополнительные средства. Минус — лишний цикл и расход памяти на больших выборках.
Единственный вариант внутри запроса на старых платформах. Годится только для строк фиксированной структуры с известными позициями символов.
Нестандартные и невидимые символы
На практике частая проблема — неразрывные пробелы, табуляции и символы переноса строки, которые визуально неотличимы от обычного пробела, но не совпадают с ним при сравнении. В запросе их можно указать через функцию СИМВОЛ() с кодом символа:
СТРЗАМЕНИТЬ(Номенклатура.Наименование, СИМВОЛ(160), " ") КАК Наименование
Здесь СИМВОЛ(160) — неразрывный пробел, который заменяется на обычный. Коды часто встречающихся невидимых символов:
| Символ | Код | Где появляется |
|---|---|---|
| Неразрывный пробел | 160 | Копирование из Excel, веб-страниц, печатных форм |
| Табуляция | 9 | Импорт из табличных файлов |
| Перенос строки | 10 | Многострочные поля, выгрузки |
| Возврат каретки | 13 | Файлы, подготовленные в Windows |
Для очистки многострочного текста от переводов строк обычно нужны две вложенные замены: сначала СИМВОЛ(13) на пустую строку, затем СИМВОЛ(10) на пробел или нужный разделитель.
Если замена «не срабатывает» хотя символ визуально присутствует, почти всегда дело в невидимом символе с другим кодом. Быстрый способ диагностики — встроенной функцией КодСимвола() в коде посмотреть коды подозрительных позиций строки, а затем использовать СИМВОЛ() с найденным кодом в запросе.
Проверка результата и типичные ошибки
После написания запроса проверьте его в консоли запросов на реальных данных, особенно на записях с «грязными» значениями. Полезно вывести рядом исходное и преобразованное поле, чтобы визуально сравнить результат:
ВЫБРАТЬ
Номенклатура.Артикул КАК Было,
СТРЗАМЕНИТЬ(Номенклатура.Артикул, " ", "") КАК Стало
ИЗ
Справочник.Номенклатура КАК Номенклатура
Как проверить результат
Символ заменён или удалён во всех вхождениях
Заменено только частично или строка вернулась без изменений
Строки вернулись без изменений, без NULL
Появились NULL или пустые строки там, где были данные
Запрос отрабатывает за приемлемое время на рабочем объёме
Запрос «висит» — вероятно, замена используется в соединении без индекса
Когда замену лучше вынести из запроса
Язык запросов не единственное и не всегда лучшее место для обработки строк. Переносите замену во встроенный язык, если нужно заменить много разных символов (более трёх-четырёх), если логика зависит от условий, или если требуется регулярное выражение — в запросе их нет в принципе.
Если одна и та же нормализация нужна регулярно (например, поиск контрагентов по очищенному телефону), правильное архитектурное решение — хранить нормализованное значение в отдельном реквизите, заполнять его при записи объекта и индексировать. Тогда запросы остаются простыми и быстрыми, а замена выполняется один раз при записи, а не при каждом чтении.
Как выбрать действие
Что важно запомнить
В запросе 1С символы заменяются функцией СТРЗАМЕНИТЬ (платформа 8.3.6 и новее): она заменяет все вхождения одной подстроки, чувствительна к регистру и не работает с индексами в условиях. Невидимые символы задаются через СИМВОЛ(код). На старых платформах и при сложной логике замену выполняют функцией СтрЗаменить() во встроенном языке после выполнения запроса.
Частые вопросы
Заменяет ли СТРЗАМЕНИТЬ все вхождения или только первое?
Функция заменяет все вхождения искомой подстроки в строке. Отдельного параметра для ограничения количества замен нет. Если нужно заменить только первое вхождение, придётся комбинировать ПОДСТРОКА с конкатенацией или выполнять обработку в коде.
Почему запрос с СТРЗАМЕНИТЬ выдаёт ошибку «Функция не найдена»?
Функция доступна в языке запросов начиная с платформы 8.3.6. Проверьте версию платформы, под которой запускается база (помощью «О программе» или через Метаданные.Версия в коде — точнее, ТекущаяВерсияПлатформы из системной информации). Если версия ниже, используйте СтрЗаменить() во встроенном языке после выполнения запроса.
Как убрать из строки сразу несколько разных символов?
Один вызов СТРЗАМЕНИТЬ обрабатывает одну подстроку. Для нескольких символов вызовы вкладывают друг в друга: внутренний результат передаётся первым параметром во внешний вызов. При количестве символов больше трёх-четырёх читабельнее сделать обработку в цикле по таблице результата функцией СтрЗаменить() в коде.
Замена не срабатывает, хотя символ точно есть в строке. В чём причина?
Чаще всего причина две: регистр букв не совпадает (замена регистрозависима) или в данных стоит невидимый символ с другим кодом — например, неразрывный пробел (код 160) вместо обычного. Определите фактический код символа функцией КодСимвола() в коде и используйте в запросе СИМВОЛ() с этим кодом.
Можно ли использовать СТРЗАМЕНИТЬ в параметре виртуальной таблицы?
Нет, в параметрах виртуальных таблиц допустимы только константы, параметры запроса и простые выражения над ними. Сначала вычислите замену в отдельном запросе или в коде, передайте результат как параметр, а затем используйте его в виртуальной таблице.
Что вернёт СТРЗАМЕНИТЬ, если исходная строка NULL?
Если любой из параметров равен NULL, результатом будет NULL. При работе с необязательными строковыми реквизитами и левых соединениях оборачивайте поле в ЕСТЬNULL(Поле, "") до вызова замены, чтобы не потерять строки в результате.