Как реализовать поиск по сложному шаблону с символами * и ? в 1С

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

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

Разбор логики оператора ПОДОБНО

Для решения подобных задач в языке запросов 1С существует специальный оператор ПОДОБНО (в английском варианте LIKE). Однако его синтаксис отличается от того, что привык вводить пользователь. Рассмотрим соответствие символов:

  1. Символ % (процент) в 1С соответствует любому количеству произвольных символов. Это прямой аналог пользовательской «звездочки» (*).
  2. Символ _ (подчеркивание) соответствует одному произвольному символу. Это аналог пользовательского знака вопроса (?).

Таким образом, наша первая задача при получении шаблона от пользователя — преобразовать его в формат, понятный SQL-серверу и платформе 1С.

Шаг 1. Подготовка шаблона на встроенном языке

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


// Получаем шаблон из реквизита формы
ШаблонДляЗапроса = Объект.ШаблонПоиска;

// Выполняем последовательную замену
ШаблонДляЗапроса = СтрЗаменить(ШаблонДляЗапроса, "*", "%");
ШаблонДляЗапроса = СтрЗаменить(ШаблонДляЗапроса, "?", "_");

Важный нюанс: согласно условиям задачи, логины состоят только из латинских букв и цифр. Если бы в логинах могли встречаться сами символы % или _, нам пришлось бы использовать конструкцию СПЕЦСИМВОЛ (ESCAPE) для их экранирования, чтобы запрос не воспринял их как команды фильтрации.

Шаг 2. Построение запроса для выборки данных

Теперь рассмотрим, как использовать подготовленную строку в запросе. Нам необходимо выбрать данные из табличной части документа и сравнить реквизит Логин с нашим шаблоном. Выясним причину, по которой важно правильно типизировать данные.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ПользователиПользователи.Номер КАК НомерСтроки,
    |	ПользователиПользователи.ФИО КАК ФИО,
    |	ПользователиПользователи.Логин КАК Логин
    |ИЗ
    |	Документ.Пользователи.Пользователи КАК ПользователиПользователи
    |ГДЕ
    |	ПользователиПользователи.Ссылка = &СсылкаНаДокумент
    |	И ПользователиПользователи.Логин ПОДОБНО &Шаблон
    |УПОРЯДОЧИТЬ ПО
    |	НомерСтроки";

Запрос.УстановитьПараметр("СсылкаНаДокумент", Объект.ДокументСсылка);
Запрос.УстановитьПараметр("Шаблон", ШаблонДляЗапроса);

РезультатЗапроса = Запрос.Выполнить();

Шаг 3. Решение проблемы сортировки числовых номеров

Проанализируем ситуацию, упомянутую в обсуждении на форуме: как будут сортироваться номера строк? Если поле Номер в табличной части имеет строковый тип, то при обычной сортировке мы получим порядок: 1, 10, 2, 20. Это называется лексикографической сортировкой.

Чтобы отчет вывел данные в правильном математическом порядке, в запросе следует использовать приведение типов или заранее убедиться, что реквизит имеет числовой тип. Если это строка, используем ВЫРАЗИТЬ:


// В тексте запроса заменим сортировку
|УПОРЯДОЧИТЬ ПО
|	ВЫРАЗИТЬ(ПользователиПользователи.Номер КАК ЧИСЛО)

Однако помните, что ВЫРАЗИТЬ для строк работает не во всех СУБД одинаково. Оптимальный вариант — хранить номер в числовом реквизите.

Шаг 4. Вывод результата и подсчет итогов

После выполнения запроса нам нужно вывести данные в отчет (например, в табличный документ) и подсчитать количество найденных строк. Рассмотрим пример реализации вывода:


Выборка = РезультатЗапроса.Выбрать();

ТабДок = Новый ТабличныйДокумент;
// Здесь должен быть код вывода шапки таблицы...

КоличествоСтрок = 0;
Пока Выборка.Следующий() Цикл
    КоличествоСтрок = КоличествоСтрок + 1;
    // Код вывода строки: Выборка.НомерСтроки, Выборка.ФИО, Выборка.Логин
КонецЦикла;

// Вывод итога
Сообщить("Итого строк = " + КоличествоСтрок);

Дополнительные возможности: Регистрозависимость

Посмотрим на настройки поиска. Оператор ПОДОБНО в 1С обычно ведет себя так же, как настроена база данных SQL (Case Insensitivity). Если ваша база данных чувствительна к регистру (редкий случай для 1С), а логины в системе хранятся в разном регистре, рекомендуется использовать функцию ВРЕГ (ВЕРХНИЙ РЕГИСТР) как для поля в запросе, так и для шаблона:


|ГДЕ
|	ВРЕГ(ПользователиПользователи.Логин) ПОДОБНО ВРЕГ(&Шаблон)

Альтернативный подход: Использование регулярных выражений

Если задача усложнится (например, потребуется найти логины, где цифр не более трех), возможностей ПОДОБНО может не хватить. В таких случаях программисты 1С обращаются к объекту VBScript.RegExp через COM-соединение. Рассмотрим, как это выглядит для нашей задачи:

  1. Создаем объект: RegExp = Новый COMОбъект("VBScript.RegExp");
  2. Преобразуем наш шаблон в регулярное выражение: * превращается в .*, а ? в ..
  3. Добавляем символы начала и конца строки: ^ и $.

Пример преобразования шаблона A???B в регулярное выражение:


RegExp.Pattern = "^A...B$";
RegExp.IgnoreCase = Истина;
Если RegExp.Test(ПроверяемыйЛогин) Тогда
    // Логин подходит
КонецЕсли;

Однако для большинства олимпиадных и прикладных задач в 1С использование оператора ПОДОБНО является наиболее эффективным и быстрым способом, так как фильтрация происходит на стороне сервера базы данных.

← На главную