Каждый разработчик 1С рано или поздно сталкивается с ситуацией, когда простой и логичный код не дает ожидаемого результата. Типичный пример — попытка очистить номер документа от лишних пробелов или спецсимволов. Мы пишем код, проверяем его работу в отладчике, видим, что строка успешно преобразована, но после вызова метода Записать() пробелы волшебным образом возвращаются на свое место. В этой статье мы подробно разберем, почему так происходит, рассмотрим внутренние механизмы платформы «1С:Предприятие» и найдем правильные способы решения этой проблемы.
Рассмотрим классический пример кода, с которого часто начинаются подобные темы на форумах:
Выборка = Документы.НалоговаяНакладная.Выбрать();
Пока Выборка.Следующий() Цикл
Док = Выборка.ПолучитьОбъект();
Док.Номер = СтрЗаменить(Док.Номер, " ", "");
Док.Записать();
Сообщить(Док.Номер);
КонецЦикла;
На первый взгляд код абсолютно корректен. Мы выбираем документы, получаем объект для редактирования, используем функцию СтрЗаменить() для удаления пробелов, записываем объект и выводим результат. Однако при проверке оказывается, что в базе данных номера документов по-прежнему содержат пробелы в конце строки.
Если мы поставим точку останова в конфигураторе сразу после строки преобразования, то увидим, что в переменной Док.Номер действительно находится чистая строка без пробелов. Но как только управление проходит строку Док.Записать(), платформа заново заполняет хвостовую часть строки пробелами. Выясним, почему это происходит.
Главная причина такого поведения кроется не в ошибках кода, а в настройках метаданных конкретного документа или связанного с ним нумератора в конфигураторе. В платформе «1С:Предприятие» для реквизитов Код (у справочников) и Номер (у документов) существует важное системное свойство — «Допустимая длина».
Это свойство может принимать два значения:
СокрЛП() или СтрЗаменить() игнорируются при сохранении.Поскольку у автора вопроса в метаданных документа была установлена длина номера 16 символов с типом «Фиксированная», платформа принудительно возвращала недостающие пробелы в конец строки при каждом вызове метода Записать().
Если ваша конфигурация находится на поддержке с возможностью изменения или является полностью самописной, лучшим решением будет изменение режима допустимой длины номера. Это избавит вас от необходимости писать сложные обходные алгоритмы в коде.
Разберем по шагам, как это сделать:
НалоговаяНакладная) и откройте его свойства.После выполнения этих действий платформа перестанет автоматически дополнять номера пробелами. Теперь вы можете запустить вашу обработку, и код успешно очистит номера существующих документов.
В случае, когда база данных находится на строгой поддержке (например, это типовая «1С:Бухгалтерия», закрытая от изменений), менять метаданные нельзя. В такой ситуации программисту приходится подстраиваться под особенности хранения данных. Рассмотрим, как правильно работать с номерами фиксированной длины.
1. Очистка «на лету» при выводе на печать или выгрузке
Поскольку хранить номера в базе без пробелов физически невозможно из-за ограничений метаданных, очищать их нужно непосредственно перед выводом пользователю, отправкой по API или выгрузкой во внешние файлы (XML, Excel). Для этого используйте стандартную функцию СокрЛП():
// Очищаем номер только для передачи во внешнюю систему
НомерДляВыгрузки = СокрЛП(ДокументОбъект.Номер);
Записывать результат обратно в объект бессмысленно — это приведет к повторному заполнению пробелами.
2. Борьба с неразрывными пробелами (НПП)
Иногда обычная функция СокрЛП() не справляется с удалением невидимых символов. Это происходит, когда пользователи копируют номера документов из внешних источников (например, из писем или таблиц Excel), занося в базу так называемые неразрывные пробелы (символ с кодом Unicode 160, или Символы.НПП).
Стандартная функция СокрЛП() в старых версиях платформы или при определенных условиях может не распознавать неразрывный пробел как символ, подлежащий удалению. Чтобы гарантированно очистить строку от всех видов пробелов, используем следующую конструкцию:
ЧистыйНомер = СтрЗаменить(ДокументОбъект.Номер, Символы.НПП, "");
ЧистыйНомер = СтрЗаменить(ЧистыйНомер, " ", "");
Проанализируем эту конструкцию: сначала мы заменяем все неразрывные пробелы на пустые строки, а затем производим аналогичную операцию для обычных пробелов. Полученный результат можно безопасно использовать в печатных формах.
При работе с номерами фиксированной длины часто возникает неочевидная проблема при написании запросов. Допустим, мы ищем документ по номеру, который получили из внешнего источника без пробелов:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Ссылка
|ИЗ
| Документ.НалоговаяНакладная
|ГДЕ
| Номер = &Номер";
Запрос.УстановитьПараметр("Номер", "НО000012"); // Номер без пробелов
Если в базе данных длина номера равна 16 символам с фиксированной длиной, данный запрос может вернуть пустой результат, так как в базе фактически записано значение "НО000012 " (с восемью пробелами на конце).
Поведение этого запроса зависит от используемой СУБД:
Чтобы гарантировать стабильную работу поиска на любой СУБД, перед передачей параметра в запрос необходимо дополнить поисковую строку пробелами до нужной длины либо использовать оператор сравнения ПОДОБНО с автоподстановкой процента:
// Вариант с ПОДОБНО (может снизить производительность на больших базах)
Запрос.УстановитьПараметр("Номер", "НО000012%");
Или, что более правильно с точки зрения производительности СУБД, дополнить строку пробелами до фиксированной длины метаданных:
ПоисковыйНомер = "НО000012";
НужнаяДлина = Метаданные.Документы.НалоговаяНакладная.ДлинаНомера;
// Дополняем строку пробелами справа до нужной длины
Пока СтрДлина(ПоисковыйНомер) < НужнаяДлина Цикл
ПоисковыйНомер = ПоисковыйНомер + " ";
КонецЦикла;
Запрос.УстановитьПараметр("Номер", ПоисковыйНомер);
Мы подробно проанализировали проблему программного изменения номера документа в 1С. Подведем итог всему вышесказанному:
СокрЛП() и СтрЗаменить() непосредственно в момент выгрузки или вывода на печать.Символы.НПП), которые пользователи могут случайно скопировать в поля ввода.