Как устроен перенос строки во встроенном языке 1С:Предприятия 8.3
Содержание
Новая строка в 1С — это обычный символ внутри строки, а не отдельная команда. Во встроенном языке его дают через системное перечисление Символы: Символы.ПС (перевод строки, код 10) и Символы.ВК (возврат каретки, код 13). Внутри платформы строки хранятся с разделителем ПС, а пара ВК + ПС появляется при обмене с Windows-файлами.
Пишете "Строка 1" + Символы.ПС + "Строка 2" — получаете текст из двух строк. Он так же выведется в сообщении, в многострочном поле формы и в ячейке табличного документа. Вся остальная работа с переносами — это вопросы «как прочитать», «как записать» и «как очистить».
Какие символы переноса есть в платформе
Перечисление Символы доступно в любом модуле, на клиенте и на сервере. Для переноса и разметки текста в нём шесть значений.
| Свойство | Английское имя | Код | Что это |
|---|---|---|---|
Символы.ПС | Chars.LF | 10 | Перевод строки — основной разделитель строк в 1С |
Символы.ВК | Chars.CR | 13 | Возврат каретки, часть windows-пары CR+LF |
Символы.Таб | Chars.Tab | 9 | Горизонтальная табуляция |
Символы.ВТаб | Chars.VTab | 11 | Вертикальная табуляция |
Символы.ПФ | Chars.FF | 12 | Перевод формы (новая страница) |
Символы.НПП | Chars.NBSp | 160 | Неразрывный пробел |
Свойства Символы.НП в платформе нет. Если в чужом коде или в описании встречается такое имя, скорее всего, имели в виду Символы.НПП — неразрывный пробел. Конфигуратор на Символы.НП выдаст ошибку синтаксического контроля.
Любой символ можно получить и по коду: Символ(10) равен Символы.ПС. Обратная функция КодСимвола(Строка, Позиция) возвращает код символа в заданной позиции. Она нужна, когда непонятно, что за «невидимка» сидит в строке.
Чем ПС отличается от ВК
Исторически это две разные команды телетайпа: ВК возвращал печатающую головку в начало строки, ПС прокручивал бумагу. Сегодня операционные системы договорились по-разному:
- 🪟 Windows хранит перенос в текстовых файлах как пару
ВК + ПС(CR+LF); - 🐧 Linux и macOS используют только
ПС(LF); - ⚙️ платформа 1С внутри строк тоже работает с одиночным
ПС.
Отсюда главный практический вывод. Когда вы склеиваете строки в коде, достаточно Символы.ПС. Пара ВК + ПС нужна только тогда, когда принимающая сторона явно её требует: старый банковский формат, текстовый принтер, внешняя программа.
Перенос строки в коде: литералы, сообщения, запросы
Многострочный литерал
Строковый литерал в модуле можно разбить на несколько строк. Каждая продолжающая строка начинается с вертикальной черты |:
Текст = "Уважаемый клиент!
|Ваш заказ собран.
|Ожидайте звонка курьера.";
Пробелы и табуляция перед | в результат не попадают, поэтому код можно выравнивать отступами. Между строками платформа подставит ПС.
Тот же приём используется в тексте запроса — без него длинный запрос пришлось бы склеивать плюсами:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
Склейка и шаблоны
Для текста из переменных удобнее не плюсы, а СтрШаблон:
Текст = СтрШаблон("Документ: %1%2Сумма: %3",
Документ.Номер, Символы.ПС, Формат(Документ.СуммаДокумента, "ЧДЦ=2"));
Если строк много и они лежат в массиве, соберите их одной функцией СтрСоединить(Массив, Символы.ПС). Она появилась в платформе 8.3.6 и работает заметно быстрее, чем наращивание строки в цикле.
Сообщения пользователю
Сообщить() и Новый СообщениеПользователю выводят многострочный текст как есть. Удобно для протокола обработки: собрали ошибки в массив, соединили через ПС, показали одним сообщением вместо двадцати.
Перенос внутри запроса как значения
В языке запросов нет аналога Символы.ПС. Если нужно сравнить поле с текстом, где есть перенос, или подставить такой текст в выборку, передайте его параметром:
Запрос.УстановитьПараметр("Разделитель", Символы.ПС);
Отладка: как увидеть невидимый перенос
Перенос не виден в отладчике: строка с ПС в конце выглядит так же, как без него. Отсюда классика — Если Код = "А-100" Тогда не срабатывает, хотя глазами значения одинаковые.
Проверка занимает минуту. В точке останова откройте окно вычисления выражения (Shift+F9) и посмотрите:
СтрДлина(Код)— если длина больше видимой, в строке есть лишние символы;КодСимвола(Код, СтрДлина(Код))— код последнего символа: 10, 13, 9 или 160 сразу подскажут виновника;СтрНайти(Код, Символы.ВК)— позиция возврата каретки, 0 — если его нет.
Для массовой проверки напишите маленькую функцию, которая выводит коды всех символов строки:
Функция КодыСимволов(Стр) Экспорт
Коды = Новый Массив;
Для Поз = 1 По СтрДлина(Стр) Цикл
Коды.Добавить(Формат(КодСимвола(Стр, Поз), "ЧГ=0"));
КонецЦикла;
Возврат СтрСоединить(Коды, " ");
КонецФункции
Для строки "А1" + Символы.ВК + Символы.ПС она вернёт 1040 49 13 10. Сразу видно и кириллическую «А», и хвост из двух служебных символов.
Новая строка при чтении и записи файлов
ЧтениеТекста и ЗаписьТекста
Оба объекта принимают параметры, которые управляют переносами: разделитель строк в файле и конвертируемый разделитель внутри 1С. По умолчанию платформа пишет в файл пару ВК + ПС, а внутренние ПС при записи превращает в эту пару. При чтении работает обратное преобразование.
Значит, для обычного Windows-файла хватает вызова по умолчанию:
Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
Запись.ЗаписатьСтроку("Первая строка");
Запись.ЗаписатьСтроку("Вторая строка");
Запись.Закрыть();
Если получатель — Linux-сервис или скрипт, которому нужен чистый LF, передайте разделитель явно третьим параметром:
Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8, Символы.ПС);
Построчное чтение идёт через ПрочитатьСтроку(), который возвращает Неопределено, когда файл кончился:
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
Стр = Чтение.ПрочитатьСтроку();
Пока Стр <> Неопределено Цикл
// обработка строки
Стр = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
ТекстовыйДокумент
Объект ТекстовыйДокумент удобен, когда нужен доступ к строке по номеру: КоличествоСтрок(), ПолучитьСтроку(Номер), ДобавитьСтроку(). Метод Записать() тоже принимает кодировку и разделитель строк. Для небольших файлов это самый короткий путь, для файлов в сотни мегабайт лучше потоковое ЧтениеТекста — весь документ держится в памяти.
CSV, JSON, XML
| Формат | Как ведёт себя перенос | Что делать |
|---|---|---|
| CSV | Перенос внутри значения ломает строку файла на две | Значение с ПС, ; или кавычками заключайте в двойные кавычки, внутренние кавычки удваивайте |
| JSON | ЗаписьJSON сама экранирует перенос как \n | Ничего, при чтении через ЧтениеJSON перенос вернётся символом |
| XML | По стандарту XML парсер при чтении сводит CR+LF и одиночный CR к LF | Не рассчитывайте сохранить ВК в тексте XML-узла |
Если файл уходит в банк, ФНС-шлюз или старую учётную программу, смотрите спецификацию формата, а не угадывайте. Один неверный разделитель строк — и файл отклоняется целиком.
Переносы в макетах и печатных формах
В табличном документе перенос внутри текста ячейки работает: строка "ООО «Ромашка»" + Символы.ПС + "ИНН 7700000000" выведется в две строки. Чтобы обе были видны, нужны два условия:
- 📐 У ячейки или области включено размещение текста с переносом. В коде это
Область.РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Переносить, в макете — свойство размещения текста в палитре свойств ячейки. - 📏 Высота строки не зафиксирована вручную. Иначе вторая строка уйдёт под границу ячейки.
Для длинных назначений платежа и адресов перенос включают всегда: даже без ПС текст разобьётся по ширине колонки. Явный ПС нужен, когда разрыв должен стоять в конкретном месте — например, наименование и реквизиты на разных строках.
Правка макета типовой печатной формы прямо в основной конфигурации снимает её с поддержки и мешает обновлениям. Изменения макетов типовых форм делайте через расширение конфигурации или через пользовательские макеты, если конфигурация их поддерживает.
Многострочное поле на форме
Чтобы пользователь видел и вводил несколько строк, у поля ввода управляемой формы включают свойство МногострочныйРежим и задают высоту поля больше одной строки. Значение реквизита при этом — обычная строка с ПС внутри. Реквизит неограниченной длины подходит лучше: у строки фиксированной длины текст обрежется.
Очистка текста от переносов и пустых строк
Данные из Excel, почты и сайтов почти всегда приходят с мусором. Типовые операции укладываются в несколько строк кода.
Убрать переносы по краям
СокрЛП(Стр) отсекает пробелы и другие незначащие символы слева и справа, включая переносы и табуляцию. Для полей вроде кода, артикула или ИНН это первая строка обработки. СокрЛ и СокрП делают то же только с одной стороны.
Склеить многострочный текст в одну строку
Стр = СтрЗаменить(Стр, Символы.ВК, "");
Стр = СтрЗаменить(Стр, Символы.ПС, " ");
Стр = СтрЗаменить(Стр, Символы.Таб, " ");
Порядок важен: сначала удаляем ВК, потом меняем ПС на пробел. Иначе из пары ВК + ПС получится лишний символ.
Привести все переносы к одному виду
Если текст пришёл из разных источников, нормализуйте его до любой обработки:
Стр = СтрЗаменить(Стр, Символы.ВК + Символы.ПС, Символы.ПС);
Стр = СтрЗаменить(Стр, Символы.ВК, Символы.ПС);
После этого в строке остаются только ПС, и все функции разбора ведут себя предсказуемо.
Удалить пустые строки
СтрРазделить с третьим параметром Ложь выбрасывает пустые элементы. Пустые строки из одних пробелов она не уберёт, поэтому их сокращаем вручную:
Части = СтрРазделить(Стр, Символы.ПС, Ложь);
Результат = Новый Массив;
Для Каждого Часть Из Части Цикл
Часть = СокрЛП(Часть);
Если ЗначениеЗаполнено(Часть) Тогда
Результат.Добавить(Часть);
КонецЕсли;
КонецЦикла;
Стр = СтрСоединить(Результат, Символы.ПС);
Подсчитать и перебрать строки
Для многострочного текста есть две старые функции: СтрЧислоСтрок(Стр) возвращает количество строк, СтрПолучитьСтроку(Стр, Номер) — строку по номеру, нумерация с 1. Обе рассчитаны на разделитель ПС, поэтому текст с windows-переносами сначала нормализуйте.
На больших текстах СтрПолучитьСтроку в цикле медленная: каждый вызов заново ищет нужную строку от начала. Для тысяч строк выгоднее один раз вызвать СтрРазделить и идти по массиву.
Нестандартные случаи
Числа с неразрывным пробелом
Excel и веб-страницы разделяют разряды неразрывным пробелом. Число("1 250,50") с таким символом упадёт с ошибкой преобразования. Перед конвертацией уберите и Символы.НПП, и обычные пробелы:
Стр = СтрЗаменить(СтрЗаменить(Стр, Символы.НПП, ""), " ", "");
Вставка из буфера в табличную часть
Пользователь копирует колонку из Excel и вставляет в поле. В значении оказываются Таб между ячейками и переносы между строками. Если вы разбираете такую вставку кодом, делите сначала по ПС, потом каждую строку — по Символы.Таб.
Перевод формы и текстовые принтеры
Символы.ПФ в обычной учётной работе почти не встречается. Он нужен, когда 1С формирует текстовый файл для матричного или чекового принтера: символ с кодом 12 означает «начать новую страницу». В печатных формах на табличном документе разрывы страниц задаются иначе — горизонтальным разделителем страниц, а не символом.
HTTP-заголовки и параметры
Перенос внутри значения HTTP-заголовка недопустим: значение заголовка не может содержать символы с кодами 10 и 13. Если в заголовок попадает строка из реквизита, пропустите её через СокрЛП и замену переносов — иначе запрос уйдёт с ошибкой или сервер его отклонит.
Частые вопросы
Как вставить перенос строки в строку 1С?
"Строка 1" + Символы.ПС + "Строка 2". В тексте модуля можно также написать многострочный литерал с вертикальной чертой | в начале каждой продолжающей строки.Чем Символы.ПС отличается от Символ(10)?
Символы.ПС читается легче и не требует помнить коды.Нужно ли писать ВК + ПС в коде для Windows?
ПС, а при записи файла через ЗаписьТекста платформа сама подставит нужный разделитель. Пару вручную добавляйте только когда собираете строку для внешнего получателя без записи через платформенные объекты.Почему СтрЧислоСтрок показывает на одну строку больше?
СокрП перед подсчётом.Как найти, есть ли в строке перенос?
СтрНайти(Стр, Символы.ПС) > 0 — перенос есть. Для ВК проверка такая же. Функция СтрНайти доступна с платформы 8.3.6, в более ранних версиях использовали Найти.