Перенос строки в коде 1С 8.3: от Символы.ПС до макетов и запросов

· 9 мин

Содержание

Перенос строки в 1С 8.3 даёт системный объект Символы: выражение Символы.ПС возвращает перевод строки (символ с кодом 10), а Символы.ВК — возврат каретки (код 13). Чтобы разбить текст на две строки, достаточно склеить части через этот символ: "Первая строка" + Символы.ПС + "Вторая строка". Тот же результат даёт функция Символ(10).

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

Символ перевода строки: Символы.ПС, Символы.ВК и Символ()

В 1С 8.3 за непечатаемые символы отвечает глобальный объект Символы. Это не перечисление из конфигурации, а встроенное свойство платформы, доступное в любом модуле. Его члены:

  • 📄 Символы.ПС — перевод строки, LF, код 10. Основной символ переноса.
  • ↵ Символы.ВК — возврат каретки, CR, код 13.
  • ➡️ Символы.Таб — горизонтальная табуляция, код 9.
  • ⬇️ Символы.ПД — перевод формата (form feed), код 12.
  • ␣ Символы.НПП — неразрывный пробел, код 160.

Для простого переноса внутри приложения хватает одного Символы.ПС. Пара Символы.ВК + Символы.ПС даёт «виндовый» перенос CRLF — он нужен, когда текст уйдёт во внешний файл или систему, которая ждёт именно такую последовательность.

Член объектаКодНазначение
Символы.ПС10перевод строки, основной перенос
Символы.ВК13возврат каретки, вместе с ПС даёт CRLF
Символы.Таб9табуляция, разделитель колонок
Символы.ПД12перевод формата (разрыв страницы)
Символы.НПП160неразрывный пробел

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

// Три равнозначных способа получить перенос
Текст1 = "Строка один" + Символы.ПС + "Строка два";
Текст2 = "Строка один" + Символ(10) + "Строка два";
Текст3 = СтрШаблон("Строка один%1Строка два", Символы.ПС);

Функция Символ(КодСимвола) возвращает символ по его числовому коду Unicode, а КодСимвола(Строка, Позиция) делает обратное — узнаёт код символа. Это запасной путь, когда под рукой нет готового члена Символы: Символ(9) — табуляция, Символ(13) — возврат каретки.

В длинных текстах удобнее СтрШаблон: подставляете %1 вместо символа переноса, и строка остаётся читаемой. Платформа сама склеит части.

Многострочные сообщения пользователю

Самый частый сценарий — вывести пользователю несколько строк одним сообщением. Если тема про перенос строки пришла из задачи «показать текст в несколько абзацев», то речь почти всегда про это.

Метод Сообщить просто склеивает текст, переносы внутри него отрабатывают:

Текст = "Проверка завершена." + Символы.ПС
      + "Найдено ошибок: " + Ошибок + Символы.ПС
      + "Исправлено автоматически: " + Исправлено;
Сообщить(Текст);

Обратите внимание на типизацию: число нельзя «сложить» со строкой через + молча в любой ситуации — платформа приведёт его к строке, но для управляемого вида лучше Формат(Ошибок, "ЧГ=0"), иначе большое число выведется с разделителями групп по умолчанию.

Для привязки сообщения к конкретному полю формы используют объект СообщениеПользователю. В нём переносы в тексте тоже сохраняются:

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнен контрагент." + Символы.ПС + "Укажите его в шапке документа.";
Сообщение.Поле = "Объект.Контрагент";
Сообщение.Сообщить();

Когда строк заранее не известно — например, копите протокол загрузки по ходу цикла — наращивайте текст тем же символом и выводите в конце одним сообщением:

Протокол = "";
Для Каждого Строка Из ЗагружаемыеДанные Цикл
	Результат = ЗагрузитьСтроку(Строка);
	Протокол = Протокол + Строка.Номер + ": " + Результат + Символы.ПС;
КонецЦикла;
Сообщить(Протокол);

Так пользователь получит один аккуратный список, а не десятки отдельных всплывающих строк.

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

Переносы в макетах и печатных формах

В табличном документе (макете печатной формы) перенос строки работает на двух уровнях — в самом тексте ячейки и в её свойствах.

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

Перенос из данных. Если ячейка — параметр, и значение приходит из кода с Символы.ПС, то видимые переносы появятся только при включённом переносе по словам. Откройте свойства ячейки (Alt+Enter на ячейке или палитра свойств) и задайте свойство Размещение = Переносить. Тогда длинный текст и символы Символы.ПС внутри него разложатся на несколько строк по ширине ячейки.

ОбластьМакета.Параметры.Адрес = Город + Символы.ПС + Улица + Символы.ПС + Индекс;

Значения свойства Размещение:

ЗначениеЧто делает с текстом
Автокак у родителя/по умолчанию
Переноситьпереносит по словам, показывает Символы.ПС
Обрезатьобрезает по границе ячейки
Забиватьзаполняет область повторением

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

Перенос строк в тексте запроса

Здесь кроется распространённое заблуждение. Символ | (вертикальная черта) в тексте запроса — это не перенос данных в результате, а продолжение строковой константы в коде. Он позволяет писать запрос в несколько строк модуля, оставаясь читаемым:

Запрос = Новый Запрос;
Запрос.Текст =
	"ВЫБРАТЬ
	|	Номенклатура.Наименование КАК Наименование,
	|	Номенклатура.Артикул КАК Артикул
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура";

Черта в начале каждой строки говорит компилятору: «это всё ещё одна строковая константа». В сам текст запроса и в результат эти переносы не попадают.

Вставить перенос строки прямо в выбираемое поле средствами языка запросов нельзя. В запросе нет оператора конкатенации строк через +, поэтому «склеить поле с Символы.ПС» внутри ВЫБРАТЬ не получится. Перенос добавляют уже в коде, после выборки:

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
	СтрокаДляПечати = Выборка.Наименование + Символы.ПС + "Артикул: " + Выборка.Артикул;
	// дальше работаем со СтрокаДляПечати
КонецЦикла;

Если же строковое поле в базе уже содержит переносы (например, многострочный реквизит «Комментарий»), запрос вернёт их как есть — ломать или чистить их не нужно.

Разбор многострочного текста из файлов и обменов

Обратная задача — не собрать, а разобрать текст по строкам. Данные из CSV, txt-выгрузки банка или ответа внешнего сервиса приходят одной строкой с разделителями Символы.ПС или Символы.ВК + Символы.ПС.

Самый удобный инструмент — СтрРазделить:

Строки = СтрРазделить(ПолныйТекст, Символы.ПС, Ложь);
Для Каждого Строка Из Строки Цикл
	Строка = СокрЛП(Строка); // убираем хвостовой Символы.ВК и пробелы
	Если ПустаяСтрока(Строка) Тогда
		Продолжить;
	КонецЦикла;
	ОбработатьСтроку(Строка);
КонецЦикла;

Третий параметр Ложь отбрасывает пустые элементы. Есть и парные функции для построчной работы без разбиения в массив:

  • СтрЧислоСтрок(Текст) — сколько строк в тексте (считает по Символы.ПС).
  • СтрПолучитьСтроку(Текст, Номер) — вернуть строку с заданным номером.
  • СтрСоединить(Массив, Символы.ПС) — собрать массив обратно в многострочный текст.

Файлы из Windows приходят с переносом CRLF. Если разделять только по Символы.ПС, в конце каждой строки останется невидимый Символы.ВК (код 13). Он портит сравнение строк и поиск по справочнику. Снимайте его через СокрЛП или СтрЗаменить(Текст, Символы.ВК, "").

Для больших файлов вместо чтения целиком в память берут объект ЧтениеТекста и метод ПрочитатьСтроку() — он сам распознаёт перенос и отдаёт строки по одной.

Обратная операция — выгрузка многострочного текста в файл. Здесь перенос выбираете вы, и для совместимости с Windows-программами берут CRLF:

Запись = Новый ЗаписьТекста("C:\Обмен\выгрузка.txt", КодировкаТекста.UTF8);
Для Каждого Элемент Из Данные Цикл
	Запись.ЗаписатьСтроку(Элемент.Код + Символы.Таб + Элемент.Наименование);
КонецЦикла;
Запись.Закрыть();

Метод ЗаписатьСтроку сам добавит перевод строки после каждой записи. Если собираете текст вручную через +, перенос между записями ставьте сами и не забудьте про кодировку: несовпадение кодировки, а не переносов, — вторая по частоте причина «кракозябр» в выгрузке.

Разделитель колонок и разделитель строк — разные вещи. Между полями одной строки ставьте Символы.Таб или ;, а между строками — Символы.ПС. Их путаница ломает разбор файла у получателя.

Отображение переносов в тонком и веб-клиенте

Один и тот же Символы.ПС рисуется по-разному в зависимости от того, куда он попал.

Поле ввода на форме. Чтобы пользователь мог вводить и видеть многострочный текст, у поля задают свойство МногострочныйРежим = Истина. Без него перенос в значении есть, но поле покажет только первую строку.

Надпись (декорация). Элемент-надпись на управляемой форме отображает Символы.ПС как перенос и в тонком, и в веб-клиенте — дополнительной настройки не требуется.

Поле HTML-документа. Если текст выводится через поле типа «Поле HTML документа», переносом служит тег <br>, а не Символы.ПС. Перед выводом замените одно на другое:

ТекстHTML = СтрЗаменить(ИсходныйТекст, Символы.ПС, "<br>");

Веб-клиент и буфер обмена. При копировании многострочного значения из веб-клиента браузер может нормализовать переносы под свою ОС. На бизнес-логику это не влияет: внутри базы хранится ровно то, что вы записали. Если текст уходит во внешнюю систему по жёсткому формату, фиксируйте перенос явно (Символы.ВК + Символы.ПС), не полагаясь на клиента.

Форматированный документ и подсказки. В элементе типа «Поле форматированного документа» перенос ставится самим редактором, а программно — методами объекта ФорматированныйДокумент, где абзацы разделяются своими элементами, а не символом Символы.ПС в тексте. А вот всплывающая подсказка (РасширеннаяПодсказка) и заголовок колонки Символы.ПС понимают и переносят текст в обоих клиентах.

Важный вывод для кроссклиентного кода: логику формирования текста с Символы.ПС пишите один раз на сервере, а особенности отображения закрывайте настройкой конкретного элемента формы. Тогда один и тот же результат корректно покажется и в тонком, и в веб-клиенте без веток «если веб-клиент».

Частые ошибки при работе с переносами

Диагностика: выберите симптом

Ещё одна тонкая ошибка — путать Символы.ПС и Символы.ВК. По отдельности для вывода внутри 1С работает любой, но при выгрузке в строго форматированный файл (платёжки, обмены) порядок и состав важны: стандарт Windows — именно Символы.ВК + Символы.ПС, в этом порядке.

Частые вопросы

Чем отличается Символы.ПС от Символы.ВК?
Символы.ПС — перевод строки (LF, код 10), Символы.ВК — возврат каретки (CR, код 13). Для вывода внутри 1С достаточно Символы.ПС. Для файлов в формате Windows нужна пара Символы.ВК + Символы.ПС.
Можно ли вставить перенос строки прямо в строковую константу?
В коде перенос добавляют символом: "..." + Символы.ПС + "...". Живой перенос с клавиатуры внутри кавычек не делают — для многострочных текстов запроса используют продолжение строки через |.
Как посчитать количество строк в многострочном тексте?
Функцией СтрЧислоСтрок(Текст) — она считает строки по символу Символы.ПС. Отдельную строку вернёт СтрПолучитьСтроку(Текст, Номер).
Почему перенос есть в данных, но не виден на печати?
У ячейки макета не включён перенос по словам. Откройте свойства ячейки и задайте Размещение = Переносить.
Как убрать переносы из строки?
Заменой на пробел или пустую строку: СтрЗаменить(СтрЗаменить(Текст, Символы.ВК, ""), Символы.ПС, " "). Сначала убирают Символы.ВК, затем Символы.ПС.