Ноль, которого не видно: что Формат печатает пустотой

06.10.26

Разработка - Механизмы платформы 1С

В отчете колонка «Сумма». В одной строке пусто, в соседней 0,00. Пользователь спрашивает, чем они отличаются, и ответ неприятен: в первой ровно ноль, а во второй четыре тысячных. Настоящий ноль платформа печатает пустотой, а почти ноль — нулем. Для читателя отчета это ровно наоборот: пустая ячейка выглядит как «данных нет». В статье замеренная таблица: что именно печатается пустотой, почему ЧН это не формат, а подстановка текста, и один ключ форматной строки, который молча игнорируется из-за пробела в значении без кавычек. Вторая часть — про то же с другой стороны. Структура.Свойство при отсутствующем ключе не оставляет переменную прежней, а затирает ее. У таблицы-реквизита формы нет метода Найти. А ноль, записанный как 0,00, функция БСП читает обратно как Неопределено. Все протоколы замеров приложены.

В отчете колонка «Сумма». Две строки рядом: в первой пусто, во второй 0,00. Пользователь спрашивает, чем они отличаются. Мы в такой ситуации обычно лезем смотреть данные, а дело не в данных. Правильный ответ неприятен: в первой строке ровно ноль, а во второй — четыре тысячных.

Формат(0,     "ЧДЦ=2")  ->  []
Формат(0.004, "ЧДЦ=2")  ->  [0,00]

То есть настоящий ноль платформа печатает пустотой, а почти ноль — нулем. Для читателя отчета это ровно наоборот: пустая ячейка выглядит как «данных нет», а 0,00 — как «данные есть, и это ноль».

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

Замеры 01.10.2026, платформа 8.5, Бухгалтерия 3.0.206, русская локализация.

 

Пустота по умолчанию

Ноль печатается пустотой не из-за формата, а вообще:

Что печатаем Результат
Формат(0, "") пусто
Формат(0, "ЧДЦ=2") пусто
Формат(0, "ЧДЦ=2; ЧГ=0") пусто
Формат(0.00, "ЧДЦ=2") пусто
Формат(Неопределено, "ЧДЦ=2") пусто
Формат("", "ЧДЦ=2") пусто

 

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

И тут же асимметрия, с которой статья началась:

 

Значение С ЧДЦ=2
0 пусто
0.004 0,00
-0.004 0,00
0.005 0,01

 

Округление работает до проверки на ноль. Значение, которое округлилось в ноль, нулем для платформы не стало — она печатает его как 0,00. Поэтому в одной колонке соседствуют пустота и 0,00, и это не ошибка отчета.

 

Сколько видов пустоты

Четыре: ровно ноль, Неопределено, пустая строка и пустая дата. В готовой ячейке они неразличимы.

 

ЧН — это не формат, а текст

Лечится ключом ЧН. Вот как он себя ведет:

 

Форматная строка Результат
ЧН=0 0
ЧН=0; ЧДЦ=2 0
ЧДЦ=2; ЧН=0 0
ЧН=0,00 0,00
ЧН=0.00 0.00

 

Смотрите на последние три строки. ЧН не форматирует ноль, а подставляет вместо него текст. Написали ЧН=0 — получите 0, без копеек, сколько бы ни стояло в ЧДЦ. Написали ЧН=0.00 с точкой — точка и напечатается, в русской локали, где разделитель запятая.

Отсюда практическое следствие. Чтобы получить в ячейке 0,00, писать надо ЧДЦ=2; ЧН=0,00 — то есть повторить формат руками внутри подстановки. ЧДЦ=2; ЧН=0 даст 0 и сломает выравнивание колонки по разрядам.

И еще: порядок ключей не важен, ЧН выигрывает у ЧДЦ в любом случае. А ЧВН= (вывод пустого числа) ноль не возвращает — остается пусто.

 

Ключ, который молчит из-за пробела

С пустой датой та же история, и чинится она ключом ДП. На этом я и сел.

Формат(Дата(1,1,1), "ДФ=dd.MM.yyyy; ДП=нет даты")    ->  []
Формат(Дата(1,1,1), "ДФ=dd.MM.yyyy; ДП='нет даты'")  ->  [нет даты]

Первая строка — не «ключ не работает». Это значение с пробелом без кавычек, и платформа в таком случае не ругается, а молча не применяет ключ. Результат ровно такой же, как если бы ДП там не было вовсе.

Без пробела все работает и без кавычек:

 

Форматная строка Результат
ДП=нетданных нетданных
ДП=- -
ДФ=dd.MM.yyyy; ДП=- -
ДЛФ=D; ДП=нетданных нетданных
ДП='нет даты' нет даты
ДП="нет даты" нет даты

 

Кавычки годятся и одинарные, и двойные. Правило простое: есть пробел — ставьте кавычки, и не надейтесь, что про опечатку в форматной строке вам скажут.

Отдельно отмечу П= — такого ключа нет. Ни для даты, ни для числа он ничего не меняет, и, разумеется, молча.

 

Два случая, которые ломают сравнение

Пока были в форматной строке, замерились еще две вещи, которые обычно находят не там, где они живут.

Разряды разделяются неразрывным пробелом. Формат(1234567.89, "") дает 1 234 567,89, и пробелы там с кодом 160, а не 32. Такую строку не сравнить с той, что пришла из файла, и обратно в число она не превращается. Отключается через ЧГ=0.

Числовой формат не применяется к булеву. Формат(Ложь, "ЧДЦ=2") возвращает Нет. Если колонка динамически получает то число, то булево — а это обычное дело для вычисляемых полей с ВЫБОР, — в ней появятся Да и Нет там, где ждали цифры.

Заодно: Формат(-5, "ЧО=0") печатает (5). Отрицательное в скобках, без минуса. Для бухгалтерской формы это то, что нужно, а для выгрузки в файл — источник веселья на стороне получателя.

 

Часть вторая: пустота, которая приходит из чтения

Теперь про то же самое с другой стороны. Пустота в ячейке может прийти не из формата, а из того, что значение не прочиталось.

Привычная мысль: Структура.Свойство("Ключ", Знач) — безопасное чтение, вернет Ложь, если ключа нет, и переменную не тронет. Половина этой мысли неверна:

Знач = 999;
Нашлось = С.Свойство("Нету", Знач);
// Нашлось = Ложь, а Знач стало Неопределено

Переменная затирается. Не остается прежней, не остается 999 — становится Неопределено. Значит типовой прием «положу значение по умолчанию, а потом попробую прочитать» не работает: при отсутствии ключа значение по умолчанию исчезает.

Писать надо так:

Знач = 999;
Если С.Свойство("Нету") Тогда
	Знач = С.Нету;
КонецЕсли;

То есть сначала проверить, потом читать. Либо не забывать восстанавливать значение после неудачного чтения — но первый вариант короче и не требует помнить про эту грабельку.

Остальные способы чтения ведут себя предсказуемо и единообразно:

 

Что читаем, когда значения нет Что возвращается
Соответствие.Получить("Нету") Неопределено
Массив.Найти("Нету") Неопределено
ТаблицаЗначений.Найти("нету", "А") Неопределено
Структура.Нету через точку исключение: «Поле объекта не обнаружено (Нету)»

 

И отдельно про таблицы на форме, потому что они ведут себя не как таблицы значений. Реквизит формы объявлен как ТаблицаЗначений, а строка у него — ДанныеФормыЭлементКоллекции, тип другой:

 

Что пробуем на таблице-реквизите формы Что получаем
ТаблицаДанных.Найти("нету", "А") метода нет: «Метод объекта не обнаружен (Найти)»
Строка.Получить(0) метода нет
Строка[0] = "значение" «Получение элемента по индексу для значения не определено»
Строка["А"] = "значение" работает
Строка.А = "значение" работает

 

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

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

 

И обратно: ноль, записанный с копейками, не читается

Самое смешное в этой истории — что круг замыкается полностью. Напечатали ноль как 0,00, сохранили в файл, прочитали обратно — и ноль не вернулся.

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

 

Вход Число() СтрокаВЧисло
-1 500 с обычным пробелом исключение -1500
(1500) исключение -1500
пустая строка исключение 0
0 0 0
0,00 0 Неопределено

 

Последняя строка и есть тихий угол. Настоящий ноль, записанный с копейками, возвращается как Неопределено — то есть неотличимо от мусора вроде abc. Пустая строка при этом честно даст ноль.

Причина в последней строке тела функции: результат возвращается только если он не равен нулю и строка после чистки не пуста. Ноль с копейками не проходит ни по первому условию, ни по второму.

Хорошая новость: Неопределено в арифметике падает сразу и громко. Плохая — ровно поэтому его часто оборачивают в ?(Рез = Неопределено, 0, Рез), и вот тут громкая ошибка снова становится тихим нулем. Минус U+2212 и тире U+2013 функция тоже не понимает, так что нормализация символов нужна все равно.

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

 

Как это искать в своем коде

Все описанное выше не ломается в момент написания. Оно ломается позже, когда в данные приходит настоящий ноль или пустая строка, а до тех пор код выглядит работающим и проходит любую проверку.

Поэтому искать надо не ошибки, а места, где ошибка станет возможной. Три приметы.

Вызов Формат без явного ключа для нуля. Если в форматной строке есть ЧДЦ, но нет ни ЧН, ни чего-то другого, что задает поведение на нуле, это место когда-нибудь напечатает пустоту. В отчете, где ноль означает «нет движения», пустой окажется ровно та строка, которую читатель будет искать глазами.

Значения ключей, в которых есть пробел. Пробел без кавычек превращает ключ в молчащий. Ищется это легко: смотреть в форматных строках пробел, стоящий после знака равенства и не взятый в кавычки. Платформа про такое не скажет ничего, ни при компиляции, ни при исполнении.

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

 

Чего этот замер не покрывает

Границы лучше назвать прямо, чтобы на статью не ссылались шире, чем она проверена.

Все замеры сняты на одной локализации и в одном типе сеанса. Про сеанс, где разделителем целой и дробной части служит точка, тут не утверждается ничего. И это не мелочь: соседний разбор показывает, что одна и та же строка в разных сеансах превращается в разные числа.

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

И последнее. Четыре утверждения про разбор строки в число взяты из прогона на другой платформе и в другой день. Они помечены отдельно не потому, что в них есть сомнение, а потому, что замер в одной пачке и замер в двух это разные вещи.

 

Что с этим делать

В отчетах задавать ЧН явно там, где ноль значащий. В остатках, в количестве, в разнице — пустая ячейка вместо нуля читается как «не считали». И писать ЧН=0,00, а не ЧН=0, если в колонке есть копейки.

Не принимать пустоту за отсутствие данных. Пустая ячейка в 1С значит одно из четырех: ровно ноль, Неопределено, пустая строка или пустая дата. Если это различие важно — печатайте его сами.

В форматной строке брать значения с пробелами в кавычки. И проверять результат глазами: об опечатке в форматной строке платформа не сообщает.

Безопасное чтение делать в два шага. Проверить наличие, потом читать. Одношаговый вариант со значением по умолчанию это значение теряет.

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

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

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

Про обратную сторону этой же истории — что платформа делает, когда в типизированный реквизит кладут значение не того типа, — у меня есть отдельный разбор: там "12,5" превращается в 12,5 или в 125 в зависимости от сеанса.

А какой ключ форматной строки вас подводил молча?

Вступайте в нашу телеграмм-группу Инфостарт

Формат ЧН ЧДЦ ДП форматная строка пустая дата неразрывный пробел СтрокаВЧисло БСП ноль в отчете пустая ячейка Неопределено печатная форма табличный документ числовой формат отладка отчета Структура.Свойство значение по умолчанию внешняя обработка 1С 8.5

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Механизмы платформы 1С Разработчик Бесплатно (free)

Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?

16.07.2025    45679    TitanLuchs    109    

156

Работа с интерфейсом WEB-интеграция Механизмы платформы 1С Бесплатно (free)

Веб-интерфейсы повышают качество внешнего вида приложений 1С, предсказуемы с точки зрения верстки, позволяют организовать удобные и высокопроизводительные рабочие места для пользователей. Расскажем об особенностях разработки веб-интерфейсов на React внутри 1С, двустороннем взаимодействии 1С и JavaScript, а также сборке веб-приложения в одностраничный файл.

19.06.2025    18698    zeegin    15    

64

Механизмы платформы 1С Работа с интерфейсом Разработчик Стажер 1С:Предприятие 8 Бесплатно (free)

Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).

03.02.2025    26038    bayselonarrend    127    

68

Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)

В этой статье подробно рассматривается работа с JSON в XDTO в 1С:Предприятие. Вы узнаете, как сериализовать и десериализовать объекты XDTO в JSON, интегрировать 1С с веб-сервисами и API, а также корректно обрабатывать данные при обмене. Разбираются особенности работы с коллекциями, использование функций восстановления и частые ошибки при работе с JSON и XDTO.

30.01.2025    33321    user2122906    10    

69

Механизмы платформы 1С Файловый обмен (TXT, XML, DBF), FTP Разработчик 1С:Предприятие 8 Бесплатно (free)

Этот материал познакомит вас с механизмом XDTO (XML Data Transfer Objects) в 1С и научит эффективно использовать его возможности. Мы разберёмся, как работать с XML-схемами, создавать модели данных, манипулировать объектами XDTO, а также сериализовать и десериализовать их в XML. Вы узнаете, как использовать XDTO для интеграции с внешними системами, избегать типичных ошибок и оптимизировать код. К концу вы будете уверенно применять XDTO для решения сложных задач обмена данными и автоматизации процессов.

17.01.2025    55814    user2122906    13    

63

Механизмы платформы 1С WEB-интеграция Разработчик 1С:Предприятие 8 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    46797    dsdred    110    

160

Механизмы платформы 1С Разработчик Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    40469    bayselonarrend    24    

180
Для отправки сообщения требуется регистрация/авторизация