ПОДОБНО в запросе 1С проверяет строку по шаблону: начинается ли она с нужных символов, заканчивается ли ими, подходит ли под маску артикула. Простой случай «наименование содержит подстроку» разобран в статье о строковых функциях в запросе. Здесь — всё остальное: наборы символов в квадратных скобках, СПЕЦСИМВОЛ, шаблон в параметре, поиск по нескольким словам и по артикулу, регистр, индексы и замена ведущего %.
Условие записывается так: Выражение [НЕ] ПОДОБНО Шаблон [СПЕЦСИМВОЛ "символ"]. Шаблон сравнивается со всей строкой: Наименование ПОДОБНО "кабель" без процентов найдёт только товар с наименованием ровно «Кабель». Служебные символы: % — любое количество любых символов, в том числе ни одного; _ — ровно один символ; [...] — один символ из набора или диапазона; [^...] — один символ не из набора. Спецсимвол делает следующий за ним служебный символ обычным.
| Шаблон | Что найдёт |
|---|---|
"Кабель%" | Начинается с «Кабель»: «Кабель ВВГ 3х1,5», «Кабель-канал 40х25» |
"%мм" | Заканчивается на «мм» |
"%ВВГ%2,5%" | Оба фрагмента, причём именно в этом порядке |
"А-___" | «А-» и ровно три символа: «А-101», «А-12Б»; «А-1000» не подходит |
"[0-9]%" | Первый символ — цифра |
"[ABC]%" | Первый символ — A, B или C |
"[^0-9]%" | Первый символ — не цифра; пустую строку не найдёт |
"%[0-9][0-9][0-9][0-9]" | Заканчивается четырьмя цифрами |
"%~%%" СПЕЦСИМВОЛ "~" | Содержит сам знак процента: «Скидка 10%» |
"%" | Любую строку, включая пустую, но не NULL |
Регулярных выражений здесь нет: [0-9] — ровно один символ, повторений и альтернатив не бывает, поэтому маски получаются фиксированной длины. Пример — контроль справочника: найти артикулы не по маске «две латинские буквы, дефис, четыре цифры» и сразу подписать причину.
// Общий модуль КонтрольНоменклатуры (флажок «Сервер»).
// Артикулы, которые не подходят под маску «две латинские буквы, дефис, четыре цифры».
Функция ПроблемныеАртикулы() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Артикул КАК Артикул,
| ВЫБОР
| КОГДА Номенклатура.Артикул ПОДОБНО ""% %""
| ТОГДА ""Пробел в артикуле""
| КОГДА Номенклатура.Артикул ПОДОБНО ""%~_%"" СПЕЦСИМВОЛ ""~""
| ТОГДА ""Подчеркивание вместо дефиса""
| КОГДА Номенклатура.Артикул ПОДОБНО ""[^A-Z]%""
| ТОГДА ""Первый символ не латинская буква""
| ИНАЧЕ ""Не по маске AA-0000""
| КОНЕЦ КАК Проблема
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления
| И Номенклатура.Артикул <> """"
| И НЕ Номенклатура.Артикул ПОДОБНО ""[A-Z][A-Z]-[0-9][0-9][0-9][0-9]""
|
|УПОРЯДОЧИТЬ ПО
| Проблема,
| Артикул";
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
НЕ ... ПОДОБНО "[A-Z][A-Z]-[0-9][0-9][0-9][0-9]" — каждая пара скобок проверяет одну позицию, длина маски ровно семь символов."[^A-Z]%" ловит кириллические «А», «В», «С», набранные вместо латинских: на экране артикул тот же, а поиск по нему не срабатывает."%~_%" СПЕЦСИМВОЛ "~" ищет сам знак подчёркивания. Без СПЕЦСИМВОЛ шаблон "%_%" подходит к любой непустой строке.Наборы работают в файловой базе, на MS SQL и PostgreSQL, но стандарт 1С №726 для тиражных конфигураций разрешает только % и _: исключением, где квадратные скобки не работают, он называет IBM DB2. Латиница и цифры в диапазонах безопасны, а кириллический [а-я] на разных СУБД может по-разному обойтись с буквой «ё».
Шаблон передают параметром, а проценты добавляют в коде. УстановитьПараметр служебные символы не экранирует: если пользователь ввёл «10%» или «ГОСТ_2», его % и _ станут частью маски и найдут лишнее. Поэтому сначала экранируем ввод, потом достраиваем шаблон.
// Общий модуль ПоискНоменклатуры (флажки «Сервер» и «Вызов сервера»).
// Экранирует служебные символы ПОДОБНО. В запросе к шаблону добавляют СПЕЦСИМВОЛ "~".
Функция ЭкранироватьДляПодобно(Знач Текст) Экспорт
Результат = СтрЗаменить(Текст, "~", "~~"); // сначала сам спецсимвол
Результат = СтрЗаменить(Результат, "%", "~%");
Результат = СтрЗаменить(Результат, "_", "~_");
Результат = СтрЗаменить(Результат, "[", "~[");
Результат = СтрЗаменить(Результат, "]", "~]");
Результат = СтрЗаменить(Результат, "^", "~^");
Возврат Результат;
КонецФункции
// Режим: "Начинается", "Заканчивается" или "Содержит".
Функция НайтиПоНаименованию(Знач СтрокаПоиска, Знач Режим = "Содержит") Экспорт
СтрокаПоиска = Лев(СокрЛП(СтрокаПоиска), 100);
Если СтрДлина(СтрокаПоиска) < 2 Тогда
Возврат Новый Массив; // пустой ввод превратился бы в "%%" - весь справочник
КонецЕсли;
Шаблон = ЭкранироватьДляПодобно(СтрокаПоиска);
Если Режим = "Начинается" Тогда
Шаблон = Шаблон + "%";
ИначеЕсли Режим = "Заканчивается" Тогда
Шаблон = "%" + Шаблон;
Иначе
Шаблон = "%" + Шаблон + "%";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 50
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ ""~""
| И НЕ Номенклатура.ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| Наименование";
Запрос.УстановитьПараметр("Шаблон", Шаблон);
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
~ на ~~. Если сделать это последним, удвоятся и тильды, которые поставили предыдущие замены.СПЕЦСИМВОЛ "~" в тексте запроса обязателен: без него ~% означает «тильда и дальше что угодно».Лев(..., 100) обрезает ввод. Стандарт ограничивает шаблон 1024 символами, при превышении платформа сообщает «Длина шаблона поиска превышает максимально возможную для используемой СУБД».ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе() с тем же спецсимволом «~».Собирать шаблон в тексте запроса стандарт 1С №726 запрещает: ПОДОБНО "%" + &Строка + "%" или поле другой таблицы в роли шаблона — нарушение. Шаблон — литерал или параметр, а спецсимвол — строковый литерал ровно из одного символа.
Пользователь вводит «кабель медный 2,5», а в справочнике — «Кабель ВВГнг 3х2,5 медный». Шаблон "%кабель%медный%" требует порядка слов и этот товар не найдёт. Надёжнее отдельное условие на каждое слово, соединённое через И.
// Общий модуль ПоискНоменклатуры: каждое слово есть в наименовании, порядок любой.
Функция НайтиПоСловам(Знач СтрокаПоиска) Экспорт
МаксимумСлов = 5;
Разделители = " " + Символы.Таб + Символы.НПП;
Слова = СтрРазделить(Лев(СтрокаПоиска, 200), Разделители, Ложь);
Запрос = Новый Запрос;
Условия = Новый Массив;
Для Каждого Слово Из Слова Цикл
Если СтрДлина(Слово) < 2 Тогда
Продолжить; // одиночные буквы и цифры почти не сужают выборку
КонецЕсли;
ИмяПараметра = "Слово" + Формат(Условия.Количество() + 1, "ЧГ=0");
Условия.Добавить("Номенклатура.Наименование ПОДОБНО &" + ИмяПараметра + " СПЕЦСИМВОЛ ""~""");
Запрос.УстановитьПараметр(ИмяПараметра, "%" + ЭкранироватьДляПодобно(Слово) + "%");
Если Условия.Количество() = МаксимумСлов Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Если Условия.Количество() = 0 Тогда
Возврат Новый Массив;
КонецЕсли;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 100
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления
| И " + СтрСоединить(Условия, Символы.ПС + Символы.Таб + "И ") + "
|
|УПОРЯДОЧИТЬ ПО
| Наименование";
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
&Слово1, &Слово2 и так далее, а слова пользователя попадают в значения. Кавычка или процент во вводе запрос не сломают.ИЛИ и берите всю группу в скобки. И связывает сильнее, чем ИЛИ: без скобок отбор по пометке удаления применится только вместе с первым словом.СтрРазделить() и СтрСоединить() доступны с версии 8.3.6.Если артикул введён целиком, ищите равенством: оно точнее и быстрее. ПОДОБНО нужен, когда помнят только часть артикула. Удобная выдача: сначала точное совпадение, затем артикулы, которые начинаются с введённого, потом остальные.
// Общий модуль ПоискНоменклатуры: точное совпадение артикула - первым в списке.
Функция НайтиПоАртикулу(Знач Артикул) Экспорт
Артикул = Лев(СокрЛП(Артикул), 50);
Если СтрДлина(Артикул) < 3 Тогда
Возврат Новый Массив;
КонецЕсли;
Экранированный = ЭкранироватьДляПодобно(Артикул);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 20
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Артикул КАК Артикул,
| ВЫБОР
| КОГДА Номенклатура.Артикул = &Артикул
| ТОГДА 0
| КОГДА Номенклатура.Артикул ПОДОБНО &НачинаетсяС СПЕЦСИМВОЛ ""~""
| ТОГДА 1
| ИНАЧЕ 2
| КОНЕЦ КАК Приоритет
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул ПОДОБНО &Содержит СПЕЦСИМВОЛ ""~""
| И НЕ Номенклатура.ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| Приоритет,
| Артикул";
Запрос.УстановитьПараметр("Артикул", Артикул);
Запрос.УстановитьПараметр("НачинаетсяС", Экранированный + "%");
Запрос.УстановитьПараметр("Содержит", "%" + Экранированный + "%");
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
ВЫБОР КОГДА — обычное логическое выражение. Здесь оно не фильтрует, а вычисляет приоритет для сортировки.AB12% и %AB12%.Номер ПОДОБНО "%123" вместе с Дата МЕЖДУ &Начало И &Конец. СУБД может сначала отобрать документы периода по индексу даты и проверить шаблоном только их."%КАБЕЛЬ%" найдёт «кабель». Во встроенном языке наоборот: СтрНайти() и сравнение строк через = регистр учитывают."%елка%" не найдёт «Ёлка». Выход — отдельное поле для поиска, где «ё» заменена на «е» (листинг 5).= не сравнить: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины…». ПОДОБНО для неё допустим, но индекса нет — сужайте период.Индекс хранит значения отсортированными, как словарь. Шаблон "Кабель%" — это диапазон от «Кабель» до следующего слова, и СУБД находит его по индексу за несколько чтений. Шаблон "%кабель%" диапазоном не описать: СУБД читает и проверяет каждую строку таблицы. На 20 тысячах товаров разницы не видно, на миллионе записей — секунды на каждый поиск.
Что помогает: индексированное условие рядом (период, владелец, родитель), отдельное поле для поиска и полнотекстовый поиск.
Отдельное поле решает две задачи. В нём артикул хранится нормализованным: заглавными, без пробелов, дефисов и точек, с латиницей вместо похожей кириллицы. А перевёрнутая копия превращает «заканчивается на 345» в «начинается с 543», то есть в поиск по индексу.
// 1. Модуль объекта справочника Номенклатура (в типовой - расширение с &После("ПередЗаписью")).
// Новые реквизиты АртикулПоиск и АртикулПоискОбратный: Строка(50), Индексирование - Индексировать.
Процедура ПередЗаписью(Отказ)
Если ЭтоГруппа Тогда
Возврат;
КонецЕсли;
// Без проверки ОбменДанными.Загрузка: товары из обмена тоже должны находиться
АртикулПоиск = ПоискНоменклатуры.НормализоватьАртикул(Артикул);
АртикулПоискОбратный = ПоискНоменклатуры.ПеревернутьСтроку(АртикулПоиск);
КонецПроцедуры
// 2. Общий модуль ПоискНоменклатуры.
Функция НормализоватьАртикул(Знач Артикул) Экспорт
Результат = СтрЗаменить(ВРег(СокрЛП(Артикул)), "Ё", "Е");
Кириллица = "АВЕКМНОРСТУХ"; // буквы, похожие на латинские
Латиница = "ABEKMHOPCTYX";
Для Позиция = 1 По СтрДлина(Кириллица) Цикл
Результат = СтрЗаменить(Результат, Сред(Кириллица, Позиция, 1), Сред(Латиница, Позиция, 1));
КонецЦикла;
Лишние = " -./\,_%[]^~"; // разделители и служебные символы ПОДОБНО
Для Позиция = 1 По СтрДлина(Лишние) Цикл
Результат = СтрЗаменить(Результат, Сред(Лишние, Позиция, 1), "");
КонецЦикла;
Возврат Результат;
КонецФункции
Функция ПеревернутьСтроку(Знач Текст) Экспорт
Результат = "";
Для Позиция = 1 По СтрДлина(Текст) Цикл
Результат = Сред(Текст, Позиция, 1) + Результат;
КонецЦикла;
Возврат Результат;
КонецФункции
// ПоОкончанию = Истина: артикул заканчивается введенными символами.
Функция НайтиПоАртикулуБыстро(Знач СтрокаПоиска, Знач ПоОкончанию = Ложь) Экспорт
Ключ = НормализоватьАртикул(Лев(СтрокаПоиска, 50));
Если СтрДлина(Ключ) < 3 Тогда
Возврат Новый Массив;
КонецЕсли;
ИмяПоля = ?(ПоОкончанию, "АртикулПоискОбратный", "АртикулПоиск");
Шаблон = ?(ПоОкончанию, ПеревернутьСтроку(Ключ), Ключ) + "%";
Запрос = Новый Запрос;
Запрос.Текст = СтрЗаменить(
"ВЫБРАТЬ ПЕРВЫЕ 50
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.#Поле ПОДОБНО &Шаблон", "#Поле", ИмяПоля);
Запрос.УстановитьПараметр("Шаблон", Шаблон);
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
AB12345.ОбменДанными.Загрузка = Истина: прочие обработчики пропустят свою логику, а поля поиска заполнятся.Для слов в любом месте наименования или описания вместо "%слово%" подойдёт полнотекстовый поиск: он идёт по заранее построенному индексу, а не по таблице.
// Общий модуль ПоискНоменклатуры: полнотекстовый поиск вместо ПОДОБНО "%слово%".
Функция НайтиПолнотекстово(Знач СтрокаПоиска) Экспорт
Найденные = Новый Массив;
Если ПустаяСтрока(СтрокаПоиска)
Или ПолнотекстовыйПоиск.ПолучитьРежимПолнотекстовогоПоиска() <> РежимПолнотекстовогоПоиска.Разрешить Тогда
Возврат Найденные;
КонецЕсли;
СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок(СтрокаПоиска, 50);
СписокПоиска.ОбластьПоиска.Добавить(Метаданные.Справочники.Номенклатура);
СписокПоиска.ПолучатьОписание = Ложь; // описание найденного не нужно, так быстрее
Попытка
СписокПоиска.ПерваяЧасть();
Исключение
// Например, синтаксическая ошибка в строке поиска
ЗаписьЖурналаРегистрации("ПоискНоменклатуры", УровеньЖурналаРегистрации.Предупреждение, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Найденные;
КонецПопытки;
Для Каждого ЭлементСписка Из СписокПоиска Цикл
Найденные.Добавить(ЭлементСписка.Значение);
КонецЦикла;
Возврат Найденные;
КонецФункции
ОбластьПоиска ограничивает поиск одним справочником, иначе в списке окажутся документы и другие объекты.ПерваяЧасть() обёрнута в Попытку.кабел*.ПОДОБНО &Строка со значением «кабель» найдёт только наименование ровно «Кабель».invalid regular expression: invalid character range: скобки стали набором, а «S-L» — диапазоном в обратном порядке.Труба 1/2" закрывает строковый литерал раньше времени, и запрос падает с ошибкой «Синтаксическая ошибка» или «Незавершенный литерал строки». Лечится только параметром.&Слово3 в текст и пропустить УстановитьПараметр: «Не задано значение параметра "Слово3"».Новый Запрос в процедуре &НаКлиенте не скомпилируется: «Тип не определен (Запрос)».НЕ Т.Поле ПОДОБНО "%а%" не вернёт строки, где Поле равно NULL. Пишите НЕ ЕСТЬNULL(Т.Поле, "") ПОДОБНО "%а%".Поставьте перед ним спецсимвол и объявите его в условии: Наименование ПОДОБНО "%~%%" СПЕЦСИМВОЛ "~" найдёт «Скидка 10%». Спецсимволом выбирают знак, которого нет в данных; в типовых конфигурациях это тильда.
Средствами ПОДОБНО — нет. Отберите кандидатов запросом и проверьте каждого в коде: СтрНайти(Наименование, СтрокаПоиска) > 0 регистр различает.
Нет, только %, _, [...] и [^...]. Сложную проверку делают в два шага: широкий отбор ПОДОБНО в запросе, точная проверка в коде. В новых версиях платформы (8.3.23 и выше) во встроенном языке есть СтрПодобнаПоРегулярномуВыражению() и другие функции для регулярных выражений.
Один параметр можно использовать в запросе несколько раз: Н.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ "~" ИЛИ Н.Артикул ПОДОБНО &Шаблон СПЕЦСИМВОЛ "~". Если рядом есть другие условия, возьмите эту пару в скобки.
Быстрый поиск сразу по наименованию, артикулу и штрихкоду на справочнике в сотни тысяч позиций — это доработка с изменением метаданных, её можно заказать в разделе отчёты и обработки 1С. Опишите задачу на странице «Разместить задание», и исполнители оценят сроки и стоимость.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.