Приветствуем вас! При выгрузке данных в формат CSV из систем на платформе 1С:Предприятие 7.7 разработчики регулярно сталкиваются с нарушением структуры результирующего файла. Простая задача экспорта превращается в проблему: строки ломаются, ячейки съезжают, а итоговый документ в Microsoft Excel или сторонних парсерах выглядит хаотично. Выясним причину этой проблемы, детально проанализируем ошибки в коде и разберем наиболее эффективные и производительные способы очистки и подготовки строк к выгрузке.
Рассмотрим код, с которого часто начинают решение этой задачи разработчики:
Реквизит = СтрЗаменить(Реквизит, РазделительСтрок, "");
Реквизит = СтрЗаменить(Реквизит, Симв(13), "");
Реквизит = СтрЗаменить(Реквизит, Симв(10), "");
Реквизит = СтрЗаменить(Реквизит, Симв(121), "");
Проанализируем данную конструкцию и разберем по шагам, почему она работает неэффективно и пропускает "невидимые" символы:
Симв(121) пытается заменить в тексте символ с ASCII-кодом 121. В стандартной таблице ASCII этот код соответствует строчной латинской букве "y". Очевидно, что здесь закралась досадная опечатка, из-за которой из выгружаемых наименований или описаний просто вырезалась полезная буква, в то время как истинные виновники искажения структуры оставались на месте.Симв(9), который часто используется парсерами как разделитель колонок, вертикальную табуляцию Симв(11) (пришедшую из документов Word), перевод страницы Симв(12) или неразрывный пробел Симв(160), который ведет себя непредсказуемо в зависимости от кодировки.РазделительСтрок в 1С 7.7 возвращает пару символов Симв(13) + Симв(10) (стандарт Windows CRLF). Однако, если данные в базу импортировались из Linux-систем, веб-сервисов или внешних API, разрывы строк могут быть представлены одиночным символом Симв(10) (LF), а в старых файлах macOS — одиночным Симв(13) (CR). Одиночные символы требуют отдельной и последовательной обработки.Прежде чем приступать к тотальному удалению всех спецсимволов, давайте рассмотрим концептуально правильный подход. Согласно официальной спецификации формата CSV (RFC 4180), перенос строки внутри ячейки допускается и является абсолютно валидным. Главное условие — такое поле должно быть целиком заключено в двойные кавычки, а все имеющиеся внутри текста двойные кавычки должны быть продублированы.
Таким образом, вместо того чтобы портить исходный текст и удалять из него важное форматирование (например, абзацы в описании товара), мы можем корректно экранировать строку. Посмотрим на пример реализации этого метода на встроенном языке 1С 7.7:
// Функция для корректного экранирования поля под стандарт CSV
Функция ЭкранироватьДляCSV(ЗначениеПоля)
Перем Рез;
Рез = СокрЛП(ЗначениеПоля);
// Дублируем внутренние кавычки
Рез = СтрЗаменить(Рез, """", """""");
// Оборачиваем всё значение в кавычки
Рез = """" + Рез + """";
Возврат Рез;
КонецФункции
При использовании этого метода современные парсеры (включая Microsoft Excel, Google Таблицы и библиотеки на Python/C#) корректно распознают границы ячеек, а многострочный текст останется внутри одной ячейки, не разбивая строку таблицы.
Если бизнес-требования жестко настаивают на том, что никаких переносов строк в файле быть не должно, наилучшим решением станет использование регулярных выражений. Во встроенном языке 1С 7.7 нет собственного движка регулярных выражений, однако мы можем подключить системный COM-объект операционной системы Windows — VBScript.RegExp.
Рассмотрим подробнее особенности работы с этим объектом в среде 1С 7.7:
CreateObject().Истина и Ложь, для настройки свойств объекта RegExp необходимо передавать их числовые аналоги: -1 для включения опции (True) и 0 для её отключения (False).Разберем по шагам пример функции, которая очищает строку от всех управляющих ASCII-символов с кодами от 0 до 31, а также символа 127:
Функция ОчиститьСтрокуРегуляркой(ИсходнаяСтрока)
Перем RegExp, Результат;
// Создаем COM-объект регулярных выражений Windows
RegExp = CreateObject("VBScript.RegExp");
// Настраиваем параметры поиска
RegExp.IgnoreCase = -1; // Игнорировать регистр
RegExp.Global = -1; // Искать все вхождения в строке
RegExp.MultiLine = -1; // Включаем многострочный режим
// Шаблон [\x00-\x1F\x7F] находит любые непечатные управляющие символы ASCII
RegExp.Pattern = "[\x00-\x1F\x7F]";
// Заменяем все найденные спецсимволы на обычный пробел
Результат = RegExp.Replace(ИсходнаяСтрока, " ");
Возврат Результат;
КонецФункции
Если стоит задача оставить в выгружаемой строке только строго определенный набор "безопасных" символов (например, только буквы, цифры и базовые знаки препинания), мы можем инвертировать регулярное выражение с помощью конструкции отрицания [^...]:
Функция ОчиститьДоРазрешенных(ИсходнаяСтрока)
Перем RegExp;
RegExp = CreateObject("VBScript.RegExp");
RegExp.IgnoreCase = -1;
RegExp.Global = -1;
RegExp.MultiLine = -1;
// Оставляем только русские/английские буквы, цифры, пробелы и знаки препинания
RegExp.Pattern = "[^a-zA-Z0-9а-яА-ЯёЁ\s.,;:!?()""'\-]";
Возврат RegExp.Replace(ИсходнаяСтрока, "");
Если использование внешних COM-объектов по какой-то причине нежелательно (например, при жестких ограничениях безопасности на сервере), можно использовать проверенный метод последовательных замен через встроенную функцию СтрЗаменить. Проанализируем правильную и полную последовательность очистки:
Функция ПолнаяОчисткаСтроки(Значение)
Перем Рез;
Рез = Значение;
// 1. Избавляемся от классического виндового переноса строки CRLF
Рез = СтрЗаменить(Рез, РазделительСтрок, " ");
// 2. Заменяем одиночные символы возврата каретки (CR) и перевода строки (LF)
Рез = СтрЗаменить(Рез, Симв(13), " ");
Рез = СтрЗаменить(Рез, Симв(10), " ");
// 3. Убираем горизонтальную табуляцию (часто ломает CSV с разделителем-табом)
Рез = СтрЗаменить(Рез, Симв(9), " ");
// 4. Удаляем вертикальную табуляцию и разрывы страниц
Рез = СтрЗаменить(Рез, Симв(11), " ");
Рез = СтрЗаменить(Рез, Симв(12), " ");
// 5. Заменяем неразрывные пробелы на стандартные пробелы
Рез = СтрЗаменить(Рез, Симв(160), " ");
// 6. Удаляем двойные пробелы, которые могли образоваться после замен
Пока Найти(Рез, " ") > 0 Цикл
Рез = СтрЗаменить(Рез, " ", " ");
КонецЦикла;
Возврат СокрЛП(Рез);
КонецФункции
В ходе обсуждения на форумах часто звучит предложение перебирать строки посимвольно в цикле с использованием функций Сред() и КодСимвола(). Настоятельно рекомендуем отказаться от данного подхода при работе в 1С 7.7.
Встроенный интерпретатор "семерки" выполняет циклы на программном уровне медленно. Если в вашей выгрузке содержатся десятки тысяч номенклатурных позиций или документов, посимвольный анализ каждого текстового поля приведет к колоссальным задержкам и временному "зависанию" сессии базы данных. В то же время:
СтрЗаменить реализована на уровне ядра платформы (скомпилирована в C++) и обрабатывает большие объемы текста практически мгновенно.VBScript.RegExp также работает на уровне оптимизированных системных библиотек Windows, выполняя сложные замены на порядок быстрее любого самописного цикла.Используйте правильные инструменты, комбинируйте экранирование кавычек и регулярные выражения, и ваши файлы обмена всегда будут сохранять идеальную структуру!