При работе со строками в 1С мы часто сталкиваемся с ситуацией, когда данные, полученные из внешних источников (например, из Excel, веб-страниц или других систем), содержат невидимые служебные символы. Один из таких символов, который может вызывать недоумение, – это символ ¶ (знак абзаца). Нам кажется, что это символ табуляции или просто перевод строки, но стандартные методы замены, такие как СтрЗаменить(Наименование, Символы.Таб, "") или СтрЗаменить(Наименование, Символы.ПС, ""), не всегда срабатывают. Давайте подробно разберем, почему это происходит, как диагностировать такие символы и как эффективно от них избавиться.
Символ ¶, или знак абзаца (Pilcrow), является типографским символом, который исторически использовался для обозначения начала абзаца. В электронных текстах он часто выступает как визуальное представление непечатных символов, таких как перенос строки. В операционных системах и различных приложениях используются разные комбинации символов для обозначения конца строки или абзаца:
Символы.ПС (код 10). Он переносит курсор на одну строку вниз.Символы.ВК (код 13). Он возвращает каретку (курсор) в начало строки.В зависимости от того, откуда были скопированы данные, мы можем встретить следующие комбинации:
Символы.ВК + Символы.ПС (CRLF).Символы.ПС (LF).Символы.ВК (CR).Таким образом, если мы пытаемся удалить только Символы.ПС, а в строке находится Символы.ВК (или их комбинация), символ переноса строки может оставаться. И наоборот. Если мы видим ¶, это может быть не один символ, а целая комбинация, или просто один из этих символов.
Первым и самым важным шагом является точная диагностика того, какие именно невидимые символы присутствуют в нашей строке. Без этого мы будем действовать наугад. Рассмотрим несколько способов:
Этот метод позволяет нам пройтись по каждому символу в строке и узнать его числовой код. Это самый надежный способ выявления невидимых символов.
Для этого мы используем функции Сред() для извлечения символа и КодСимвола() для получения его числового значения. Создадим небольшой фрагмент кода:
Для Сч = 1 По СтрДлина(Наименование) Цикл
ТекСимвол = Сред(Наименование, Сч, 1);
ТекКод = КодСимвола(ТекСимвол);
Сообщить("Символ: '" + ТекСимвол + "', Код: " + ТекКод);
КонецЦикла;
После выполнения этого кода мы увидим в окне сообщений полный список всех символов строки и их кодов. Если где-то между видимыми символами мы обнаружим коды 10 (Символы.ПС), 13 (Символы.ВК), 9 (Символы.Таб) или другие неожиданные числовые значения, это и будет наш искомый невидимый символ.
XMLСтрока()Функция XMLСтрока() преобразует строку в формат, пригодный для использования в XML. При этом специальные символы, которые могут нарушить структуру XML, будут закодированы с использованием мнемоник (например,
для Символы.ВК,
для Символы.ПС). Это позволяет визуально увидеть наличие таких символов.
Выполним следующий код:
Сообщить(XMLСтрока(Наименование));
В результате мы можем увидеть что-то вроде: "Текст до переноса
Текст после переноса". Это явно указывает на присутствие комбинации Символы.ВК + Символы.ПС.
КодироватьСтроку() для URLФункция КодироватьСтроку() с параметром СпособКодированияСтроки.КодировкаURL кодирует все специальные символы в URL-формат, что также делает их видимыми.
Сообщить(КодироватьСтроку(Наименование, СпособКодированияСтроки.КодировкаURL));
В результате мы можем получить что-то вроде "Текст%0D%0AТекст", где %0D - это Символы.ВК, а %0A - Символы.ПС.
Символ() и КодСимвола()Важно понимать разницу между функциями Символ() и КодСимвола(), так как их неправильное использование является распространенной ошибкой новичков.
КодСимвола(Строка, НомерСимвола): Получает числовой код символа из строки. Например, КодСимвола("A", 1) вернет 65.Символ(Код): Преобразует числовой код в символ. Например, Символ(65) вернет "A".Когда мы хотим заменить символ по его коду, мы должны использовать функцию Символ(), чтобы получить сам символ, который нужно заменить. Неверный подход, как это было в исходной теме:
// Неправильно! Мы пытаемся заменить числовой код, а не символ
Наименование = СтрЗаменить(Наименование, КодСимвола(13), "");
Правильный подход:
// Правильно! Мы заменяем символ, соответствующий коду 13
Наименование = СтрЗаменить(Наименование, Символ(13), "");
После проведения диагностики мы часто обнаруживаем, что за визуальным символом ¶ скрывается не один, а несколько символов переноса строки, чаще всего комбинация Символы.ПС и Символы.ВК. Именно поэтому попытки заменить только один из них не приводили к успеху.
В таких случаях нам поможет последовательная замена обоих символов. Мы сначала удалим все вхождения одного символа, а затем из получившейся строки удалим все вхождения второго символа. Это гарантирует, что независимо от их порядка или наличия по отдельности, все компоненты переноса строки будут устранены.
Вот проверенное решение:
Наименование = СтрЗаменить(СтрЗаменить(Наименование, Символы.ПС, ""), Символы.ВК, "");
Рассмотрим подробнее, как это работает:
СтрЗаменить(Наименование, Символы.ПС, "") ищет в строке Наименование все вхождения символа перевода строки (LF) и заменяет их на пустую строку.LF) передается во вторую функцию СтрЗаменить(..., Символы.ВК, ""), которая затем ищет и удаляет все вхождения символа возврата каретки (CR).Таким образом, мы гарантированно удаляем оба типа символов, которые могут составлять перенос строки, независимо от их порядка или того, представлены ли они по отдельности или в комбинации CRLF.
Иногда, особенно при более сложных задачах очистки или если мы хотим быть уверены в удалении всех непечатаемых символов, можно использовать другие подходы.
СтрРазделить() и СтрСоединить()Этот метод особенно полезен, если мы хотим не просто удалить переносы строки, но и, например, объединить многострочный текст в одну строку с определенным разделителем (например, пробелом).
Разберем по шагам:
Символы.ПС + Символы.ВК. Если это не сработает (потому что используется только один символ переноса строки), то можно попробовать разделить по Символы.ПС, а потом по Символы.ВК.Пример кода:
// Попробуем сначала разделить по комбинации CRLF
ЧастиСтроки = СтрРазделить(ИсходнаяСтрока, Символы.ВК + Символы.ПС);
// Если выше не сработало, или если есть только LF или CR
Если ЧастиСтроки.Количество() = 1 И СтрДлина(ИсходнаяСтрока) > 0 Тогда
ЧастиСтроки = СтрРазделить(ИсходнаяСтрока, Символы.ПС);
КонецЕсли;
Если ЧастиСтроки.Количество() = 1 И СтрДлина(ИсходнаяСтрока) > 0 Тогда
ЧастиСтроки = СтрРазделить(ИсходнаяСтрока, Символы.ВК);
КонецЕсли;
// Объединяем части строки обратно с помощью пробела
Результат = СтрСоединить(ЧастиСтроки, " ");
Этот метод может быть значительно быстрее, чем многократные вызовы СтрЗаменить() для очень длинных строк, поскольку операции разделения и соединения часто оптимизированы.
Когда нам нужно удалить вообще все "лишние" символы, оставляя только буквы, цифры и определенные знаки пунктуации, мы можем вручную перебрать исходную строку и сформировать новую, включая только разрешенные символы.
Посмотрим на пример:
НоваяСтрока = "";
Для Сч = 1 По СтрДлина(Наименование) Цикл
ТекСимвол = Сред(Наименование, Сч, 1);
КодСимвола = КодСимвола(ТекСимвол);
// Пример: оставляем только буквы, цифры и пробел
Если (КодСимвола >= КодСимвола("а") И КодСимвола <= КодСимвола("я")) Или
(КодСимвола >= КодСимвола("А") И КодСимвола <= КодСимвола("Я")) Или
(КодСимвола >= КодСимвола("a") И КодСимвола <= КодСимвола("z")) Или
(КодСимвола >= КодСимвола("A") И КодСимвола <= КодСимвола("Z")) Или
(КодСимвола >= КодСимвола("0") И КодСимвола <= КодСимвола("9")) Или
(ТекСимвол = " ") Тогда
НоваяСтрока = НоваяСтрока + ТекСимвол;
КонецЕсли;
КонецЦикла;
Наименование = НоваяСтрока;
Этот метод требует более тщательной настройки списка разрешенных символов, но обеспечивает максимальный контроль над содержимым строки.
Для более сложных и гибких задач по очистке строк от различных нежелательных символов, включая все виды пробельных символов (табуляции, переносы строк), можно использовать регулярные выражения. В 1С для этого предназначен объект РегулярноеВыражение.
Например, для удаления всех пробельных символов (включая пробелы, табуляции, переносы строк) можно использовать шаблон \s+:
РегВыр = Новый РегулярноеВыражение("\s+"); // Шаблон для одного или нескольких пробельных символов
Наименование = РегВыр.Заменить(Наименование, " "); // Заменяем на один пробел, или на "" для полного удаления
Если нам нужно удалить только переносы строк, не трогая обычные пробелы, мы можем использовать шаблон [\r\n]+:
РегВыр = Новый РегулярноеВыражение("[\r\n]+"); // Шаблон для одного или нескольких CR или LF
Наименование = РегВыр.Заменить(Наименование, ""); // Полное удаление
Регулярные выражения предоставляют мощный инструментарий для работы со строками, но требуют некоторого изучения синтаксиса.
В БСП 1С существуют готовые функции, которые могут помочь в очистке строк, особенно если это связано с подготовкой данных для обмена. Например, функции УдалитьНедопустимыеСимволыXML() или ЗаменитьНедопустимыеСимволыXML() могут быть полезны, если проблема связана с символами, недопустимыми в XML.
Мы можем обратиться к этим функциям, если наша конфигурация использует БСП:
// Пример (требует наличия БСП и соответствующей экспортной функции)
// ОбщегоНазначения.УдалитьНедопустимыеСимволыXML(Строка);
Наличие и название таких функций может варьироваться в зависимости от версии БСП и конфигурации.
Работа со служебными символами в строках 1С требует внимательности и правильного подхода. Мы выяснили, что визуальный символ ¶ часто представляет собой комбинацию или один из символов переноса строки (Символы.ПС и Символы.ВК). Мы научились диагностировать эти невидимые символы с помощью посимвольного перебора, XMLСтрока() и КодироватьСтроку().
Главное решение проблемы заключается в последовательной замене обоих символов переноса строки: Наименование = СтрЗаменить(СтрЗаменить(Наименование, Символы.ПС, ""), Символы.ВК, "");
Кроме того, мы рассмотрели альтернативные и более универсальные методы очистки строк, такие как использование СтрРазделить() и СтрСоединить(), построение новой строки с фильтрацией символов и применение регулярных выражений. Выбор метода зависит от конкретной задачи и требований к очистке данных.