Как убрать подстроку из форматированной строки в 1С, сохранив оформление?

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

В процессе разработки на платформе 1С:Предприятие часто возникает задача динамического изменения текста, который уже имеет определенное оформление: выделение цветом, жирный шрифт или наклон. Типичная ошибка начинающего разработчика — попытка использовать стандартную функцию СтрЗаменить() напрямую к объекту типа ФорматированнаяСтрока. В этой статье мы подробно разберем, почему классический подход не работает и какими методами можно выполнить замену или удаление подстроки, сохранив при этом визуальный стиль сообщения.

Почему стандартная функция СтрЗаменить() не подходит

Разберем ситуацию: у нас есть объект ФорматированнаяСтрока. При попытке выполнить следующий код оформление мгновенно пропадает:


МояСтрока = Новый ФорматированнаяСтрока("Важное сообщение", Новый Шрифт(,,Истина), ЦветаСтиля.ЦветОшибки);
// Пытаемся удалить слово "Важное"
МояСтрока = СтрЗаменить(МояСтрока, "Важное", ""); 

Проблема заключается в том, что функция СтрЗаменить() работает исключительно с типом Строка. Как только вы передаете в нее ФорматированнаяСтрока, платформа неявно преобразует объект в обычный текст, отбрасывая всю информацию о шрифтах и цветах. На выходе вы получаете простую строку, и повторное оборачивание в конструктор Новый ФорматированнаяСтрока() уже не вернет утраченные стили. Нам необходимо работать со структурой объекта, а не с его текстовым представлением.

Способ №1: Использование объекта ФорматированныйДокумент

Наиболее надежный и «официальный» способ манипуляции сложным текстом — использование объекта ФорматированныйДокумент. Этот объект специально спроектирован для работы с размеченным текстом и позволяет программно искать и изменять фрагменты.

Рассмотрим алгоритм действий по шагам:

  1. Создадим экземпляр ФорматированныйДокумент.
  2. Загрузим в него нашу ФорматированнуюСтроку.
  3. Выполним поиск текста и получим соответствующий интервал.
  4. Удалим или заменим текст в найденном интервале.
  5. Выгрузим результат обратно.

Проанализируем пример кода:


Док = Новый ФорматированныйДокумент;
Док.УстановитьФорматированнуюСтроку(ИсходнаяФорматированнаяСтрока);

// Ищем подстроку, которую нужно удалить
НайденныйИнтервал = Док.НайтиТекст(ПодстрокаДляУдаления);

Пока НайденныйИнтервал <> Неопределено Цикл
    // Заменяем текст на пустую строку, сохраняя окружающее оформление
    НайденныйИнтервал.ЗаменитьТекст("");
    // Ищем следующее вхождение, если нужно удалить все
    НайденныйИнтервал = Док.НайтиТекст(ПодстрокаДляУдаления);
КонецЦикла;

Результат = Док.ПолучитьФорматированнуюСтроку();

Этот метод хорош тем, что ФорматированныйДокумент берет на себя всю работу по сохранению тегов оформления внутри структуры документа.

Способ №2: Перебор коллекции Элементы

Мало кто знает, что ФорматированнаяСтрока является коллекцией. Она состоит из элементов, которые могут быть либо обычными строками, либо вложенными объектами ФорматированнаяСтрока. Мы можем рекурсивно обойти эти элементы и применить замену только к текстовым частям.

Разберем, как реализовать такой обход:


Функция ОбработатьФорматированнуюСтроку(ИсходнаяСтрока, ЧтоИщем, НаЧтоМеняем)
    МассивРезультат = Новый Массив;
    
    Для Каждого Элемент Из ИсходнаяСтрока.Элементы Цикл
        ТипЭлемента = ТипЗнч(Элемент);
        
        Если ТипЭлемента = Тип("Строка") Тогда
            // Если это просто текст, выполняем обычную замену
            МассивРезультат.Добавить(СтрЗаменить(Элемент, ЧтоИщем, НаЧтоМеняем));
        ИначеЕсли ТипЭлемента = Тип("ФорматированнаяСтрока") Тогда
            // Если это вложенная строка со своим оформлением, обрабатываем ее свойства
            // В реальной задаче здесь может потребоваться рекурсия или анализ свойств Font/Color
            ТекстВнутри = СтрЗаменить(Строка(Элемент), ЧтоИщем, НаЧтоМеняем);
            МассивРезультат.Добавить(Новый ФорматированнаяСтрока(ТекстВнутри, Элемент.Шрифт, Элемент.ЦветТекста, Элемент.ЦветФона, Элемент.Гиперссылка));
        КонецЕсли;
    КонецЦикла;
    
    Возврат Новый ФорматированнаяСтрока(МассивРезультат);
КонецФункции

Важный нюанс: если искомая подстрока «разрезана» оформлением (например, часть слова жирная, а часть — обычная), этот метод потребует более сложной логики склейки текста перед поиском.

Способ №3: Работа через HTML-представление

Иногда удобнее работать с текстом как с HTML-кодом. ФорматированныйДокумент позволяет получить HTML-содержимое, в котором оформление представлено стандартными тегами (<span>, <strong> и т.д.).

Посмотрим на последовательность действий:


Док = Новый ФорматированныйДокумент;
Док.УстановитьФорматированнуюСтроку(ТвояСтрока);

ТекстHTML = "";
Вложения = Новый Структура;
Док.ПолучитьHTML(ТекстHTML, Вложения);

// Теперь ТекстHTML содержит строку с тегами. 
// ВНИМАНИЕ: Подстрока поиска может содержать спецсимволы HTML
ТекстHTML = СтрЗаменить(ТекстHTML, ПодстрокаПоиска, "");

Док.УстановитьHTML(ТекстHTML, Вложения);
Результат = Док.ПолучитьФорматированнуюСтроку();

Выясним причину осторожности при работе с HTML: если ваша подстрока содержит символы типа <, > или неразрывные пробелы, в HTML-коде они будут заменены на сущности типа &lt;, &gt; или &nbsp;. В этом случае обычный СтрЗаменить не найдет вхождение. Перед заменой рекомендуется привести искомую строку к HTML-безопасному формату.

Способ №4: Сериализация в XML (XDTO)

Для продвинутых задач можно использовать механизм сериализации XDTO. ФорматированнаяСтрока отлично сериализуется в XML. В этом формате структура данных становится прозрачной: текст отделен от атрибутов оформления.

Проанализируем ситуацию программно:


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьДанные(ЗаписьXML, МояФорматированнаяСтрока);
XMLТекст = ЗаписьXML.Закрыть();

// Выполняем замену в XML-структуре (аккуратно, чтобы не повредить теги)
XMLТекст = СтрЗаменить(XMLТекст, ПодстрокаПоиска, "");

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(XMLТекст);
Результат = СериализаторXDTO.ПрочитатьДанные(ЧтениеXML, Тип("ФорматированнаяСтрока"));

Этот метод является более стабильным, чем использование недокументированных функций типа ЗначениеВСтрокуВнутр(), так как опирается на стандартные механизмы платформы по работе с данными.

Рекомендации по проектированию

Если вы только проектируете систему, где требуется частое изменение частей форматированного текста, мы рекомендуем следующее:

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

← На главную