Как найти и удалить пробелы в наименованиях элементов справочника 1С?

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

При работе с базами данных 1С мы часто сталкиваемся с необходимостью поддерживать чистоту и порядок в справочниках. Одной из распространенных проблем является наличие лишних пробелов или других "пробельных" символов в наименованиях элементов, которые могут мешать поиску, сортировке или формированию отчетов. В этой статье мы подробно разберем, как эффективно искать и удалять такие символы, используя возможности языка запросов и встроенного языка 1С.

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

Выявляем причину: почему запрос не находит пробелы

Рассмотрим типовую ситуацию, когда мы пытаемся найти элементы справочника, наименования которых содержат пробелы. Изначально, можно предположить, что достаточно просто указать пробел в качестве параметра для оператора ПОДОБНО.

Например, если мы формируем запрос следующим образом:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Состав.Наименование,
| Состав.Ссылка
|ИЗ
| Справочник.Состав КАК Состав
|ГДЕ
| Состав.Наименование ПОДОБНО &Наименование";
Запрос.УстановитьПараметр("Наименование", " ");

В этом случае, как показал опыт автора, запрос может возвращать пустую выборку, даже если визуально мы видим пробелы в наименованиях. Причина кроется в том, что оператор ПОДОБНО в сочетании с точным значением параметра, таким как просто " ", ищет строки, которые полностью совпадают с этим параметром или начинаются/заканчиваются на него, если не используются специальные символы-шаблоны. Нам же нужно найти строки, которые содержат пробел в любой части наименования. Для быстрой отладки условий запроса и пакетной обработки полученных данных можно использовать консоль запросов с поддержкой произвольных алгоритмов обработки.

Правильный поиск элементов с пробелами в запросе 1С

Для того чтобы запрос корректно находил элементы, содержащие пробелы в любой части наименования, нам необходимо использовать специальные символы-шаблоны, которые предоставляет оператор ПОДОБНО. Главный из них – это знак процента (%), который означает любую последовательность символов (включая пустую).

Мы можем использовать его двумя основными способами.

  1. Использование параметра запроса с метасимволами:

    Мы формируем параметр таким образом, чтобы он содержал символы процента до и после искомого пробела. Это указывает системе, что до пробела и после него могут быть любые символы.

    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    | Состав.Наименование,
    | Состав.Ссылка
    |ИЗ
    | Справочник.Состав КАК Состав
    |ГДЕ
    | Состав.Наименование ПОДОБНО &Наименование";
    // Правильное использование параметра для поиска строк с пробелом
    Запрос.УстановитьПараметр("Наименование", "% %"); // Ищем хотя бы один обычный пробел
    

    После такого изменения запрос успешно найдет все элементы, в наименовании которых присутствует хотя бы один обычный пробел.

  2. Встраивание шаблона напрямую в текст запроса:

    Если нет необходимости в динамическом изменении искомого символа, мы можем встроить шаблон прямо в текст запроса. При этом важно помнить о правилах экранирования кавычек в строке запроса: каждая кавычка внутри строкового литерала удваивается.

    
    Запрос.Текст = "ВЫБРАТЬ
    | Состав.Наименование,
    | Состав.Ссылка
    |ИЗ
    | Справочник.Состав КАК Состав
    |ГДЕ
    | Состав.Наименование ПОДОБНО ""% %"""; // Обратите внимание на удвоенные кавычки
    

    Оба этих метода эквивалентны и позволяют корректно выбрать нужные элементы.

Различные виды пробельных символов и их обнаружение

Важно понимать, что "пробел" — это не всегда один и тот же символ. Помимо обычного пробела (U+0020), в строках 1С могут встречаться другие символы, которые визуально выглядят как пробелы, но имеют иные коды. Если запрос с "% %" ничего не находит, или замена пробелов не происходит, значит, в наименованиях присутствуют другие пробельные символы. Рассмотрим основные из них:

  1. Неразрывный пробел (Символы.НПП):

    Это очень распространенный символ в 1С. Он часто используется для форматирования чисел (например, "1 000 000") или для предотвращения переноса строк в определенных местах. Если вы пытались заменить Символы.НПП, а найден был обычный пробел (как в случае автора), это означает, что в базе присутствуют оба типа или только обычный пробел. Для поиска неразрывного пробела в запросе мы должны использовать Символы.НПП в параметре:

    Запрос.УстановитьПараметр("Наименование", "%"+Символы.НПП+"%");
  2. Табуляция (Символы.Таб):

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

    Запрос.УстановитьПараметр("Наименование", "%"+Символы.Таб+"%");
  3. Различные Unicode-пробелы (шпации):

    В стандарте Unicode существует множество пробельных символов (круглая, полукруглая, тонкая, волосяная шпация и др.). Их поддержка в 1С может быть ограничена, и найти их напрямую через ПОДОБНО может быть сложно. Для полного контроля и выявления всех возможных "пробельных" символов, включая экзотические Unicode-пробелы, мы можем перебирать строку посимвольно и анализировать код каждого символа.

    
    // Пример посимвольного анализа (вне запроса)
    Функция ЕстьПробельныйСимвол(СтрокаДляПроверки)
        Для Каждого Символ Из СтрокаДляПроверки Цикл
            КодСимвола = КодСимвола(Символ);
            // Проверяем, является ли символ пробельным
            // Диапазоны Unicode для различных пробельных символов
            // Например, обычный пробел (U+0020), неразрывный пробел (U+00A0)
            // Табуляция (U+0009), переводы строки (U+000A, U+000D)
            // и другие различные шпации (U+2000 - U+200A, U+202F, U+205F, U+3000)
            Если КодСимвола = 32 // Обычный пробел
                Или КодСимвола = 160 // Неразрывный пробел (NBSP)
                Или КодСимвола = 9  // Табуляция (TAB)
                // ... можно добавить другие коды, если известно, что они могут присутствовать
                Или (КодСимвола >= 8192 И КодСимвола <= 8202) // Диапазон различных шпаций (U+2000 - U+200A)
                // ... и так далее
            Тогда
                Возврат Истина;
            КонецЕсли;
        КонецЦикла;
        Возврат Ложь;
    КонецФункции
    

    Этот подход более трудоемкий, но дает полный контроль над поиском любого символа по его коду.

  4. Регулярные выражения (начиная с платформы 8.3.23):

    Это наиболее мощный инструмент для поиска и обработки строк, включая различные виды пробелов. С помощью регулярных выражений можно найти любой пробельный символ, используя метасимвол \s, который включает в себя обычные пробелы, табуляции, переводы строк и многие другие пробельные символы Unicode. Для этого в 1С доступны функции СтрНайтиПоРегулярномуВыражению, СтрЗаменитьПоРегулярномуВыражению, СтрПодобнаПоРегулярномуВыражению и объект РегулярноеВыражение.

    Пример запроса с использованием регулярных выражений для выборки:

    
    // Этот пример предполагает, что мы уже получили Наименования в выборку,
    // и теперь фильтруем их или проверяем наличие пробелов.
    // Прямое использование регулярных выражений в запросах 1С затруднено
    // до появления функций типа СтрПодобнаПоРегулярномуВыражению
    // для работы на уровне СУБД, если это реализовано.
    // Поэтому чаще всего это делается в цикле по выборке.
    
    // Предположим, мы уже получили РезультатЗапроса
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        Если СтрНайтиПоРегулярномуВыражению(Выборка.Наименование, "\s") > 0 Тогда
            Сообщить("Элемент с пробелом (любого типа): " + Выборка.Наименование);
            // Здесь можно выполнить дальнейшую обработку
        КонецЕсли;
    КонецЦикла;
    

    В более новых версиях платформы 1С мы можем использовать объект РегулярноеВыражение для более гибкого поиска и замены:

    
    РегВыражение = Новый РегулярноеВыражение("\s"); // \s соответствует любому пробельному символу
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        Если РегВыражение.Найти(Выборка.Наименование) Тогда
            Сообщить("Элемент с пробельным символом: " + Выборка.Наименование);
        КонецЕсли;
    КонецЦикла;
    

Эффективное удаление и замена пробельных символов

После того как мы успешно нашли элементы, содержащие нежелательные пробельные символы, следующим шагом является их удаление или замена. Изначально, автор темы столкнулся с тем, что даже после успешного поиска, замена с Символы.НПП не работала, так как в наименованиях были обычные пробелы.

Давайте рассмотрим различные методы замены.

  1. Замена обычных пробелов:

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

    НовоеЗначениеЭлемента.Наименование = СтрЗаменить(Выборка.Наименование, " ", "");

    Это было именно то решение, которое помогло автору темы.

  2. Замена неразрывных пробелов:

    Если требуется удалить неразрывные пробелы:

    
    НовоеЗначениеЭлемента.Наименование = СтрЗаменить(Выборка.Наименование, Символы.НПП, "");
    
  3. Удаление табуляции:

    Для удаления символов табуляции:

    
    НовоеЗначениеЭлемента.Наименование = СтрЗаменить(Выборка.Наименование, Символы.Таб, "");
    
  4. Удаление пробелов в начале/конце строки:

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

    • СокрЛ(Строка) — удаляет пробелы слева.
    • СокрП(Строка) — удаляет пробелы справа.
    • СокрЛП(Строка) — удаляет пробелы с обеих сторон строки.
    НовоеЗначениеЭлемента.Наименование = СокрЛП(Выборка.Наименование);

    Это очень полезно, так как система 1С может автоматически обрезать пробелы в начале и конце наименований при программном получении элемента, но они все равно могут существовать в базе данных и вызвать проблемы.

  5. Комплексное удаление нескольких видов пробелов:

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

    
    Функция ОчиститьНаименованиеОтПробелов(ИсходноеНаименование)
        ОчищенноеНаименование = ИсходноеНаименование;
        // 1. Заменяем неразрывные пробелы
        ОчищенноеНаименование = СтрЗаменить(ОчищенноеНаименование, Символы.НПП, "");
        // 2. Заменяем табуляции
        ОчищенноеНаименование = СтрЗаменить(ОчищенноеНаименование, Символы.Таб, "");
        // 3. Заменяем обычные пробелы (если нужно удалить их полностью или привести к одному)
        // Если нужно удалить все пробелы:
        ОчищенноеНаименование = СтрЗаменить(ОчищенноеНаименование, " ", "");
        // Если нужно оставить только один пробел между словами:
        // ОчищенноеНаименование = СокрЛП(СтрЗаменить(ОчищенноеНаименование, "  ", " "));
        // Цикл для удаления множественных пробелов (например, "текст   с   многими   пробелами" -> "текст с многими пробелами")
        Пока СтрНайти(ОчищенноеНаименование, "  ") > 0 Цикл
            ОчищенноеНаименование = СтрЗаменить(ОчищенноеНаименование, "  ", " ");
        КонецЦикла;
        // 4. Удаляем начальные и конечные пробелы
        ОчищенноеНаименование = СокрЛП(ОчищенноеНаименование);
        Возврат ОчищенноеНаименование;
    КонецФункции
    

    И затем используем ее в цикле:

    
    Пока Выборка.Следующий() Цикл
        НовоеЗначениеЭлемента = Выборка.Ссылка.ПолучитьОбъект();
        НовоеЗначениеЭлемента.Наименование = ОчиститьНаименованиеОтПробелов(Выборка.Наименование);
        НовоеЗначениеЭлемента.Записать();
    КонецЦикла;
    
  6. Использование регулярных выражений для удаления всех пробельных символов (платформа 8.3.23+):

    С помощью регулярных выражений мы можем удалить все виды пробельных символов (включая табуляции, переносы строк и различные Unicode-шпации) одним махом, используя метасимвол \s. Это наиболее универсальный и мощный метод.

    
    РегВыражение = Новый РегулярноеВыражение("\s+"); // \s+ соответствует одному или более пробельным символам
    // Если нужно удалить все пробельные символы без исключения:
    НовоеЗначениеЭлемента.Наименование = РегВыражение.Заменить(Выборка.Наименование, "");
    
    // Если нужно заменить последовательности пробелов на один обычный пробел:
    // Сначала удаляем НПП и Таб отдельно, затем чистим обычные пробелы
    ОчищенноеНаименование = СтрЗаменить(Выборка.Наименование, Символы.НПП, " ");
    ОчищенноеНаименование = СтрЗаменить(ОчищенноеНаименование, Символы.Таб, " ");
    // Затем заменяем все последовательности пробелов на один пробел
    РегВыражениеДляОбычныхПробелов = Новый РегулярноеВыражение(" +"); // Один или более обычных пробелов
    ОчищенноеНаименование = РегВыражениеДляОбычныхПробелов.Заменить(ОчищенноеНаименование, " ");
    НовоеЗначениеЭлемента.Наименование = СокрЛП(ОчищенноеНаименование);
    

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

Оптимизация массовой перезаписи элементов справочника

Когда нам предстоит обновить большое количество элементов справочника, каждая операция записи (НовоеЗначениеЭлемента.Записать()) может быть достаточно ресурсоемкой. Для ускорения процесса и обеспечения целостности данных при возможных сбоях мы настоятельно рекомендуем использовать механизм транзакций.

Транзакции позволяют объединить несколько операций записи в одну логическую единицу. Если внутри транзакции произойдет ошибка, все изменения можно будет отменить. Кроме того, групповая запись в транзакции часто выполняется быстрее, так как снижается нагрузка на СУБД.


УстановитьПривилегированныйРежим(Истина); // Внешняя обработка или некоторые сценарии могут потребовать привилегированный режим
н = 0; // Счетчик элементов в текущей транзакции
НачатьТранзакцию();

Пока Выборка.Следующий() Цикл
    НовоеЗначениеЭлемента = Выборка.Ссылка.ПолучитьОбъект();
    // Здесь применяем выбранный нами метод очистки наименования:
    НовоеЗначениеЭлемента.Наименование = СтрЗаменить(Выборка.Наименование, " ", ""); // Пример: замена обычных пробелов
    // Или используем нашу функцию ОчиститьНаименованиеОтПробелов()
    // НовоеЗначениеЭлемента.Наименование = ОчиститьНаименованиеОтПробелов(Выборка.Наименование);
    НовоеЗначениеЭлемента.Записать();

    н = н + 1;
    Если н = 100 Тогда // Коммитим транзакцию каждые 100 элементов
        ЗафиксироватьТранзакцию();
        НачатьТранзакцию();
        н = 0;
    КонецЕсли;
КонецЦикла;

// Фиксируем оставшиеся элементы, если их было меньше 100 или они были последними
Если н > 0 Тогда
    ЗафиксироватьТранзакцию();
КонецЕсли;
УстановитьПривилегированныйРежим(Ложь); // Возвращаем обычный режим, если устанавливали привилегированный

В этом примере мы фиксируем транзакцию каждые 100 записей. Число 100 является ориентировочным и может быть скорректировано в зависимости от производительности вашей системы и объемов данных. Слишком маленькое значение будет часто коммитить, слишком большое — увеличит риск потери данных при сбое внутри транзакции. Экспериментируйте для нахождения оптимального значения.

Проверка и контроль результатов

После выполнения всех операций по поиску и замене пробелов критически важно убедиться, что проблема действительно решена. Мы можем выполнить следующие шаги:

  1. Повторный запуск запроса: Запустите тот же запрос на поиск пробелов (например, ПОДОБНО "% %"). Если выборка окажется пустой, это означает, что все обычные пробелы успешно удалены.

  2. Визуальный осмотр: Откройте несколько элементов справочника, которые ранее содержали пробелы, и убедитесь, что их наименования теперь выглядят корректно.

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

  4. Использование конфигуратора: В конфигураторе 1С можно включить отображение пробелов и табуляций (через настройки параметров конфигуратора, закладка "Тексты"). Это поможет "увидеть" непечатаемые символы, если они все еще присутствуют.

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

← На главную