В процессе разработки часто возникает задача преобразования строкового номера документа или справочника. Например, когда из стандартного номера вида Р00000715 необходимо получить сокращенный вариант Р715. На первый взгляд задача кажется простой, но она таит в себе множество подводных камней, связанных с уникальностью, сортировкой и механизмами автонумерации платформы 1С:Предприятие. В этой статье мы подробно разберем несколько методов решения этой задачи, проанализируем их плюсы и минусы, а также выясним, почему простое удаление символов может привести к серьезным ошибкам в будущем.
Рассмотрим самый очевидный, но при этом самый опасный способ, который часто выбирают начинающие разработчики — использование функции СтрЗаменить. Проанализируем ситуацию на примере кода:
НовыйНомер = СтрЗаменить(СтарыйНомер, "00000", "");
Почему этот метод считается плохим? Рассмотрим номер Р00100000. Если мы применим к нему данную функцию, мы удалим не только ведущие нули, но и нули в конце или середине номера, если их последовательность совпадет с шаблоном. В итоге вместо ожидаемого Р00100000 (или сокращенного Р100000) мы получим непредсказуемый результат. Запомните: функции глобальной замены текста нельзя использовать для обработки структурированных кодов и номеров, так как они не учитывают позицию символа в строке.
Если в вашей информационной базе структура номеров жестко регламентирована (например, всегда один символ префикса и всегда пять нулей), можно воспользоваться функциями работы с подстроками. Рассмотрим, как это реализовать:
СтарыйКод = "Р00000715";
// Берем первый символ и соединяем его с частью строки, начиная с 7-го символа
НовыйКод = Лев(СтарыйКод, 1) + Сред(СтарыйКод, 7);
Этот метод работает быстро, но он абсолютно не универсален. Как только количество документов в базе превысит 999 и номер станет Р00001000, ваша логика «отрезать 5 нулей» может либо сломаться, либо начать выдавать некорректные данные. Поэтому мы рекомендуем использовать более гибкие подходы.
Один из самых надежных способов избавиться от ведущих нулей — это использование функции Число(). Платформа 1С при преобразовании строки в число автоматически игнорирует все нули, стоящие перед значащими цифрами. Разберем по шагам, как это сделать, сохранив префикс:
Посмотрим на пример кода, реализующий эту логику:
Префикс = Лев(Объект.Номер, 1); // Предположим, префикс - 1 символ
ЦифроваяЧасть = Сред(Объект.Номер, 2);
// Убираем нули через преобразование типов
ЧислоБезНулей = Число(ЦифроваяЧасть);
// Собираем обратно, используя Формат для исключения пробелов-разделителей
НовыйНомер = Префикс + Формат(ЧислоБезНулей, "ЧГ=0");
Использование Формат(..., "ЧГ=0") критически важно. Если его не указать, то для больших чисел (например, 1000) 1С может добавить неразрывный пробел как разделитель групп разрядов (получится Р1 000), что недопустимо для номера документа.
Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), программировать велосипеды не нужно. Проанализируем стандартные возможности. В БСП существуют общие модули, специально предназначенные для работы с номерами. Самый популярный метод — ПрефиксныеУзлы.УдалитьПрефиксИНулиОбъекта или аналогичные функции в модуле ОбщегоНазначения.
Рассмотрим пример использования функции для вывода номера на печать (без изменения номера в самой базе):
// В типовых конфигурациях часто доступна функция:
ПечатныйНомер = ОбщегоНазначения.ПолучитьНомерНаПечать(ЭтотОбъект.Номер);
Этот подход является наиболее правильным с точки зрения архитектуры 1С. Вы не портите данные в базе, сохраняя правильную сортировку, но при этом показываете пользователю «красивый» короткий номер.
Если вам нужно решение «в лоб» средствами встроенного языка без преобразования в число (например, если в цифровой части могут быть не только цифры), можно применить оригинальный алгоритм со времен 1С 7.7:
// Очищаем пробелы, заменяем нули на пробелы, обрезаем слева и возвращаем нули назад
ТекНомер = Сред(Номер, 2); // Работаем с частью после префикса
ТекНомер = СтрЗаменить(СокрЛ(СтрЗаменить(ТекНомер, "0", " ")), " ", "0");
НовыйНомер = Лев(Номер, 1) + ТекНомер;
Проанализируем, как это работает:
1. Мы заменяем все нули на пробелы.
2. Функция СокрЛ() удаляет все пробелы (бывшие нули) только в начале строки.
3. Затем мы заменяем оставшиеся пробелы обратно на нули. Это позволяет сохранить нули внутри числа (например, в номере 105).
Выясним причину, по которой 1С изначально использует ведущие нули. Номера документов в системе являются строковыми. Сортировка строк происходит посимвольно слева направо. Если вы удалите нули и у вас появятся номера Р1, Р2 и Р10, то при сортировке Р10 окажется между Р1 и Р2, потому что символ "1" меньше символа "2".
Последствия изменения номеров:
Записать(). Если вы меняете номер в существующем документе, используйте:
Объект.Номер = НовыйСформированныйНомер;
Объект.Записать(РежимЗаписиДокумента.Запись);
Мы рассмотрели различные способы удаления ненужных символов из номера. Для разовых задач по очистке данных подойдет метод с преобразованием в Число(). Для постоянного использования в печатных формах лучше использовать функции ОбщегоНазначения.ПолучитьНомерНаПечать(). Однако помните, что изменение структуры номера в самой базе данных — это крайняя мера, которая требует тщательной проверки механизмов уникальности.