Как обрезать строку до первого пробела в запросе 1С?

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

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

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

Решение для современных платформ (1С:Предприятие 8.3.20 и выше)

Если ваша конфигурация работает на платформе версии 8.3.20 или выше, вам крупно повезло. Начиная с этого релиза, разработчики фирмы 1С добавили в язык запросов долгожданные функции для полноценной работы со строками. Среди них наиболее важными для нашей задачи являются СТРНАЙТИ (поиск позиции символа) и ЛЕВ (выделение левой части строки заданной длины).

Рассмотрим детально, как написать такой запрос. Основная загвоздка заключается в том, что функция СТРНАЙТИ вернет 0, если пробел в строке отсутствует. Если мы передадим это значение в функцию ЛЕВ, предварительно вычтя единицу (чтобы исключить сам пробел), то получим ошибку исполнения запроса из-за отрицательного значения длины. Чтобы этого избежать, мы обязательно должны использовать проверку через конструкцию ВЫБОР КОГДА.

Проанализируем следующий пример запроса:


ВЫБРАТЬ
    ВЫБОР
        КОГДА СТРНАЙТИ(Номенклатура.Наименование, " ") > 0
            ТОГДА ЛЕВ(Номенклатура.Наименование, СТРНАЙТИ(Номенклатура.Наименование, " ") - 1)
        ИНАЧЕ Номенклатура.Наименование
    КОНЕЦ КАК НаименованиеДоПробела
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Давайте разберем по шагам, как работает этот алгоритм:

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

Борьба с неразрывными пробелами (код 160)

В реальных базах данных (особенно после импорта номенклатуры из файлов Excel) часто встречаются не обычные пробелы (код 32), а неразрывные пробелы (символ с кодом 160). Обычная функция поиска их "не видит".

Чтобы решить эту проблему в современном запросе, мы можем предварительно заменить все неразрывные пробелы на обычные с помощью функции СТРЗАМЕНИТЬ. Для этого передадим неразрывный пробел в качестве параметра запроса:


// В коде 1С подготовим параметр:
Запрос.УстановитьПараметр("НП", Символы.НПП); // или Символ(160)

Тогда текст самого запроса примет следующий вид:


ВЫБРАТЬ
    ВЫБОР
        КОГДА СТРНАЙТИ(СТРЗАМЕНИТЬ(Номенклатура.Наименование, &НП, " "), " ") > 0
            ТОГДА ЛЕВ(СТРЗАМЕНИТЬ(Номенклатура.Наименование, &НП, " "), СТРНАЙТИ(СТРЗАМЕНИТЬ(Номенклатура.Наименование, &НП, " "), " ") - 1)
        ИНАЧЕ Номенклатура.Наименование
    КОНЕЦ КАК НаименованиеДоПробела
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Такой подход гарантирует 100% результат вне зависимости от того, какой именно тип пробела использовал пользователь при вводе данных.

Решение для старых версий платформ (ниже 8.3.20)

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

Вариант 1: Жесткая проверка через ВЫБОР КОГДА и ПОДСТРОКА

Этот способ основан на последовательном переборе символов строки с помощью функции ПОДСТРОКА. Он отлично подходит, если длина искомого первого слова гарантированно невелика (например, не превышает 10-15 символов). Это решение работает очень быстро на уровне СУБД, так как не требует сложных соединений таблиц.

Давайте посмотрим на пример реализации такого запроса:


ВЫБРАТЬ
    ВЫБОР
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 2, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 1)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 3, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 2)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 4, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 3)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 5, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 4)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 6, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 5)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 7, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 6)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 8, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 7)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 9, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 8)
        КОГДА ПОДСТРОКА(Номенклатура.Наименование, 10, 1) = " " ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 9)
        ИНАЧЕ Номенклатура.Наименование
    КОНЕЦ КАК ВыделенноеСлово
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Преимущества метода: Высокая скорость работы СУБД, простота отладки.

Недостатки метода: Ограниченность длины. Если первое слово окажется длиннее, чем количество прописанных веток КОГДА, система вернет строку без обрезки.

Вариант 2: Динамический поиск через «Таблицу чисел»

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

Проанализируем алгоритм реализации этого метода:

  1. Создается временная таблица (или виртуальный выбор), содержащая ряд чисел от 1 до максимальной длины строки (например, от 1 до 100).
  2. Исходная таблица соединяется с таблицей чисел по условию: символ в строке на позиции, равной числу, является пробелом.
  3. С помощью операции группировки находится МИНИМУМ(Число) для каждого элемента — это и будет позиция самого первого пробела в строке.
  4. Во втором пакете запроса мы извлекаем подстроку от 1-го символа до длины, равной (МинимальноеЧисло - 1).

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

Рекомендация по архитектуре

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

Вместо усложнения запросов выполните предварительную обработку массива данных во временной таблице на стороне встроенного языка 1С перед передачей ее в запрос:


// Пример подготовки на встроенном языке
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
    ПозицияПробела = Найти(СтрокаДанных.Наименование, " ");
    Если ПозицияПробела > 0 Тогда
        СтрокаДанных.НаименованиеДоПробела = Лев(СтрокаДанных.Наименование, ПозицияПробела - 1);
    Иначе
        СтрокаДанных.НаименованиеДоПробела = СтрокаДанных.Наименование;
    КонецЕсли;
КонецЦикла;

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

← На главную