Почему размножаются переносы строк при обмене данными в 1С и как это исправить

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Анализируем причину возникновения проблемы

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

  1. LF (Line Feed, код 10) — стандарт для систем на базе Unix/Linux.
  2. CR + LF (Carriage Return + Line Feed, коды 13 и 10) — стандарт для операционных систем Windows.

В платформе 1С:Предприятие для обозначения переноса строки в текстовых полях чаще всего используется одиночный символ Символы.ПС (код 10). Однако при выгрузке данных в формат XML вступают в силу правила нормализации XML-документов. Согласно спецификации XML, парсеры при чтении данных могут автоматически преобразовывать одиночные символы LF в последовательность CR+LF, если среда выполнения (например, Windows) считает это стандартом.

Проблема «второй производной», упомянутая в обсуждении, возникает, когда объект проходит через цепочку баз (А -> Б -> В). При первой загрузке код 10 превращается в 13+10. При последующей выгрузке и загрузке система может увидеть в коде 13+10 уже два отдельных указания на перенос или добавить еще один символ возврата каретки, что визуально удваивает межстрочный интервал. Особенно остро это проявляется при использовании веб-сервисов, платформы версий 8.3.12–8.3.15 и механизмов XDTO.

Способ 1. Нормализация строки при загрузке в правилах конвертации

Если вы используете «Конвертацию данных 2.0» или 3.0, наиболее простым и логичным решением будет очистка строки от лишних символов непосредственно в момент получения данных в базе-приемнике. Мы можем принудительно удалить все символы возврата каретки (код 13), оставив только чистые переводы строк (код 10).

Рассмотрим пример кода, который следует разместить в обработчике «После загрузки» для конкретного свойства или всего объекта (в ПКО):


// Очищаем реквизит от лишних символов возврата каретки (ASCII 13)
ЗначениеРеквизита = Объект.Комментарий; // Замените 'Комментарий' на ваш реквизит
СимволВК = Символ(13);
Объект.Комментарий = СтрЗаменить(ЗначениеРеквизита, СимволВК, "");

Проанализируем этот код: функция СтрЗаменить находит все вхождения Символ(13) и заменяет их на пустую строку. Таким образом, в базе сохраняется только Символ(10), что гарантирует корректное отображение текста в интерфейсе 1С и предотвращает «расползание» при следующей итерации обмена.

Способ 2. Глобальная нормализация перед записью объекта

В ситуациях, когда обмен настроен через типовые механизмы БСП (Библиотека стандартных подсистем) или РИБ (Распределенные информационные базы) без возможности вмешаться в сами правила обмена, мы можем использовать модуль самого объекта. Этот метод хорош тем, что он «лечит» данные независимо от того, откуда они пришли — были ли они введены пользователем вручную или загружены из другой системы.

Разберем, как реализовать проверку в модуле справочника или документа в обработчике ПередЗаписью:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    Если ОбменДанными.Загрузка Тогда
        // Если идет загрузка, принудительно нормализуем многострочные поля
        МногострочныеПоля = "Комментарий, ОписаниеТекущихДел, СоставРабот";
        МассивПолей = СтрРазделить(МногострочныеПоля, ", ", Ложь);
        
        Для Каждого ИмяПоля Из МассивПолей Цикл
            ТекущийТекст = ЭтотОбъект[ИмяПоля];
            Если Найти(ТекущийТекст, Символ(13)) > 0 Тогда
                ЭтотОбъект[ИмяПоля] = СтрЗаменить(ТекущийТекст, Символ(13), "");
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

В данном примере мы используем флаг ОбменДанными.Загрузка, чтобы не нагружать систему лишними вычислениями при обычной работе пользователя, хотя нормализация не повредит и при ручном вводе. Мы проходим циклом по списку имен реквизитов и удаляем злополучный символ с кодом 13.

Способ 3. Защита данных через CDATA или Base64

Если вы самостоятельно разрабатываете узлы обмена через ЗаписьXML, вы можете предотвратить вмешательство XML-парсера в структуру строки. Рассмотрим два варианта.

Вариант с использованием CDATA. Секция CDATA говорит парсеру: «Не анализируй то, что внутри, это просто текст». Это позволяет передать символы 10 и 13 в первозданном виде.

Вариант с кодированием в Base64. Это самый надежный, хоть и более трудозатратный способ. Текст превращается в строку вида «0Y3RgtC+INC/0YDQuNC80LXRgA==», которая вообще не содержит переносов.

Посмотрим на логику реализации через Base64:

  1. На стороне отправителя: преобразуем строку в ДвоичныеДанные (используя кодировку UTF-8), затем в строку Base64.
  2. На стороне получателя: декодируем Base64 обратно в ДвоичныеДанные и получаем строку.

Пример кода для кодирования:


// На стороне выгрузки
ТекстДляВыгрузки = Объект.ДлинноеОписание;
ДвоичныеДанныеТекста = ПолучитьДвоичныеДанныеИзСтроки(ТекстДляВыгрузки, КодировкаТекста.UTF8);
ЗашифрованнаяСтрока = Base64Строка(ДвоичныеДанныеТекста);
// Записываем 'ЗашифрованнаяСтрока' в XML вместо обычного текста

Рекомендации по выбору решения

Подводя итоги нашего исследования, можно сформулировать следующие рекомендации:

Важно помнить, что для платформы 1С символ с кодом 10 является достаточным для корректного отображения переноса в интерфейсе. Удаление символа с кодом 13 (возврат каретки) не приведет к потере структуры текста, а лишь сделает его хранение более предсказуемым и стабильным в распределенных системах.

← На главную