Как посчитать пробелы или отобрать строки с несколькими словами в запросе 1С?

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

При решении задач нормализации данных и поиска некорректно заполненных справочников часто возникает необходимость проанализировать строковые реквизиты. Типичный пример — поиск записей, где в поле ФИО ошибочно внесены данные сразу нескольких человек через пробел, либо требуется отобрать строки, содержащие заданное количество слов.

Разберем, почему стандартные строковые функции не работают напрямую в запросе, какие существуют способы подсчета пробелов средствами языка запросов 1С и как правильно решить задачу на практике.

Ограничения языка запросов 1С при работе со строками

Встроенный язык 1С предоставляет богатый набор методов для работы с текстом (СтрНайти, СтрЧислоВхождений, СтрЗаменить, СтрРазделить). Однако в языке запросов 1С большинство из этих функций недоступны, так как текст запроса транслируется в SQL-диалект конкретной СУБД, где действуют строгие ограничения платформы.

Начиная с версии платформы 8.3.20, в язык запросов были добавлены базовые строковые операции: ДЛИНАСТРОКИ, СОКРЛ, СОКРП, СОКРЛП, ЛЕВ, ПРАВ. Тем не менее, специализированной функции для подсчета количества конкретных символов в запросе по-прежнему нет. Выясним, какими способами можно обойти это ограничение.

Способ 1. Фильтрация и оценка количества пробелов через оператор ПОДОБНО

Если нам необходимо отобрать строки, в которых содержится определенное минимальное количество пробелов (например, от 4 и более), проще всего воспользоваться оператором сопоставления с шаблоном ПОДОБНО.

Посмотрим на пример отбора записей, содержащих как минимум 4 пробела:


ВЫБРАТЬ
    ФизическиеЛица.Ссылка КАК Ссылка,
    ФизическиеЛица.Наименование КАК Наименование
ИЗ
    Справочник.ФизическиеЛица КАК ФизическиеЛица
ГДЕ
    ФизическиеЛица.Наименование ПОДОБНО "% % % % %"

Если требуется получить вычисляемое числовое поле с примерным количеством пробелов (например, до 4 включительно), применим конструкцию ВЫБОР КОГДА ... ТОГДА, проверяя шаблоны от большего количества вхождений к меньшему:


ВЫБРАТЬ
    ФизическиеЛица.Ссылка КАК Ссылка,
    ФизическиеЛица.Наименование КАК Наименование,
    ВЫБОР
        КОГДА ФизическиеЛица.Наименование ПОДОБНО "% % % %" ТОГДА 4
        КОГДА ФизическиеЛица.Наименование ПОДОБНО "% % %" ТОГДА 3
        КОГДА ФизическиеЛица.Наименование ПОДОБНО "% %" ТОГДА 2
        КОГДА ФизическиеЛица.Наименование ПОДОБНО "% %" ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ КАК КоличествоПробелов
ИЗ
    Справочник.ФизическиеЛица КАК ФизическиеЛица

Важный нюанс: шаблон вида "% % %" реагирует на любые пробелы, включая подряд идущие (двойные пробелы между словами или пробелы в начале/конце строки). Если нужно посчитать именно разделенные словами фрагменты, шаблон следует уточнить с помощью конструкции исключения символов [^ ]:


ГДЕ
    ФизическиеЛица.Наименование ПОДОБНО "%[^ ]% [^ ]% [^ ]% [^ ]%"

Такой шаблон гарантирует, что между каждым пробелом присутствует как минимум один непробельный символ.

Способ 2. Точный посимвольный подсчет в запросе через таблицу чисел

Когда требуется вычислить точное произвольное количество пробелов (или любых других символов) исключительно средствами запроса, применяют соединение с генератором чисел (декартово произведение).

Разберем по шагам логику этого подхода:

  1. Создаем временную таблицу чисел от 1 до максимальной ожидаемой длины строки.
  2. Соединяем исходные данные с таблицей чисел по условию, что позиция символа не превышает длину строки.
  3. С помощью функции ПОДСТРОКА проверяем каждый символ строки: если он равен пробелу, учитываем его.
  4. Группируем результат по объекту и агрегируем функцией КОЛИЧЕСТВО.

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


ВЫБРАТЬ 1 КАК Число ПОМЕСТИТЬ ВТ_Цифры
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ФизЛица.Ссылка КАК Ссылка,
    ФизЛица.Наименование КАК Наименование,
    КОЛИЧЕСТВО(ВТ_Цифры.Число) КАК КоличествоПробелов
ИЗ
    Справочник.ФизическиеЛица КАК ФизЛица
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Цифры КАК ВТ_Цифры
        ПО ВТ_Цифры.Число <= ДЛИНАСТРОКИ(ФизЛица.Наименование)
            И ПОДСТРОКА(ФизЛица.Наименование, ВТ_Цифры.Число, 1) = " "
СГРУППИРОВАТЬ ПО
    ФизЛица.Ссылка,
    ФизЛица.Наименование

Способ 3. Постобработка на встроенном языке

Если задача выполняется в обработке или внешнем отчете и жесткого требования сделать все исключительно одним SQL-запросом нет, наиболее производительным и надежным решением является выборка данных запросом с последующим вычислением количества пробелов на встроенном языке 1С.

Рассмотрим несколько вариантов расчета на встроенном языке:

  1. Через функцию СтрЧислоВхождений: КоличествоПробелов = СтрЧислоВхождений(Выборка.Наименование, " ");
  2. Через разность длин строк:
    
    КоличествоПробелов = СтрДлина(Выборка.Наименование) - СтрДлина(СтрЗаменить(Выборка.Наименование, " ", ""));
    
  3. Через разбиение строки на массив:
    
    МассивСлов = СтрРазделить(Выборка.Наименование, " ", Ложь);
    // Ложь исключает пустые элементы при множественных пробелах подряд
    Если МассивСлов.Количество() > 3 Тогда
        // Обнаружено более трех слов в одном реквизите
    КонецЕсли;
    

Особенности поиска склеенных ФИО

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

  1. Инициалы с пробелами (например, "Иванов И. И." — 2 пробела, как и в полном ФИО).
  2. Составные двойные фамилии и имена ("Мамин-Сибиряк", "Анна-Мария").
  3. Другие разделители между разными людьми (запятые, точки с запятой, слеши).

Для качественного анализа базы рекомендуется комбинировать поиск по пробелам с отбором по другим символам-разделителям (ПОДОБНО "%,%", ПОДОБНО "%;%"), а также использовать типовые механизмы БСП из общего модуля ФизическиеЛицаКлиентСервер для корректного разбора ФИО на составные части.

← На главную