Универсальный фильтр справочников средствами 1C   

Находясь под впечатлением обработки по фильтрации справочников средствами SQL (см. статью), решил написать свою версию обработки с использованием только стандартных средств 1С для работы с любыми базами.

Для простоты решил отказаться от диапазонов. Осталось только два шаблона * и ?, так что реализовать оказалось несложно. Зато добавилась опция поиска с учетом либо без учета регистра символов.

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

Вот как выглядит форма обработки:

Форма обработки закладка 1

А вот вторая закладка (результат):

Форма обработки закладка 2

Вот код модуля:
Перем ТекСправочник,ТЗ;
Перем Последний;
Процедура ОбрТабл()
    Если Список.КоличествоСтрок()>0 Тогда
        Предупреждение(Список.Реквизит);
    КонецЕсли;
КонецПроцедуры
//________________________________________________________
Функция ПроверкаСтроки(ПармСтрока)
    Перем ВремСтрока, Результат;
    ВремСтрока=ПармСтрока;
    ТЗ.ВыбратьСтроки();
    Результат=1;
    Пока ТЗ.ПолучитьСтроку()=1 Цикл
        Если СтрДлина(ВремСтрока)=0 Тогда
            Результат=0;
        КонецЕсли;
        ТекПропуск=ТЗ.Пропуск;
        ТекТекст=ТЗ.Текст;
        ТекДлина=ТЗ.Длина;
        Если ТекПропуск>0 Тогда
            //обрезаем
            ВремСтрока=Сред(ВремСтрока,1+ТекПропуск);
        КонецЕсли;
        Если ТекПропуск<0 Тогда
            ТекПозиция=Найти(ВремСтрока,ТекТекст);
            Если ТекПозиция>0 Тогда
                ВремСтрока=Сред(ВремСтрока,ТекПозиция+ТекДлина);
            Иначе
                Результат=0;
                Прервать;
            КонецЕсли;
        Иначе
            //=0
            Если Лев(ВремСтрока,ТекДлина)=ТекТекст Тогда
                ВремСтрока=Сред(ВремСтрока,1+ТекДлина);
            Иначе
                Результат=0;
                Прервать;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    Если (Последний=1) И (СтрДлина(ВремСтрока)>0) Тогда
        Результат=0;
    КонецЕсли;
    Возврат Результат;
КонецФункции
//________________________________________________________
Процедура ШаблонистыйШаблон()
    Состояние("Создание правил");
    ТекШаблон=СокрП(Стр);
    Если РегистрСимволов=0 Тогда
        ТекШаблон=Врег(ТекШаблон);
    КонецЕсли;
    ТекПропуск=0;
    Накопитель="";
    Если ТипЗначениястр(ТЗ)="ТаблицаЗначений" Тогда
        ТЗ.УдалитьСтроки();
    Иначе
        ТЗ=СоздатьОбъект("ТаблицаЗначений");
        ТЗ.НоваяКолонка("Пропуск","Число");
        ТЗ.НоваяКолонка("Текст","Строка");
        ТЗ.НоваяКолонка("Длина","Число",);
    КонецЕсли;
    Последний=0;
    Для к=1 по СтрДлина(ТекШаблон) Цикл
        Символ=Лев(ТекШаблон,1);
        ТекШаблон=Сред(ТекШаблон,2);
        Если Символ="*" Тогда
            Если СтрДлина(Накопитель)>0 Тогда
                ТЗ.НоваяСтрока();
                ТЗ.Пропуск=ТекПропуск;
                ТЗ.Текст=Накопитель;
                ТЗ.Длина=СтрДлина(Накопитель);
                ТекПропуск=0;
                Накопитель="";
            КонецЕсли;
            ТекПропуск=?(ТекПропуск>0,ТекПропуск,-1);
        ИначеЕсли Символ="?" Тогда
            Если СтрДлина(Накопитель)>0 Тогда
                ТЗ.НоваяСтрока();
                ТЗ.Пропуск=ТекПропуск;
                ТЗ.Текст=Накопитель;
                ТЗ.Длина=СтрДлина(Накопитель);
                ТекПропуск=0;
                Накопитель="";
            КонецЕсли;
            ТекПропуск=?(ТекПропуск>0,ТекПропуск+1,1);
        Иначе
            Накопитель=Накопитель+Символ;
        КонецЕсли;
    КонецЦикла;
    Если СтрДлина(Накопитель)>0 Тогда
        ТЗ.НоваяСтрока();
        ТЗ.Пропуск=ТекПропуск;
        ТЗ.Текст=Накопитель;
        ТЗ.Длина=СтрДлина(Накопитель);
        Последний=1;
    КонецЕсли;
КонецПроцедуры
//________________________________________________________
Процедура Сформировать()
    Перем Спр, ТекАтрибут;
    Перем ТекРезультатПроверки;
    Список.УдалитьСтроки();
    ШаблонистыйШаблон();
    ТекЭлемент=Справочники.ПолучитьЗначение(Справочники.ТекущаяСтрока());
    ТекРеквизит=Реквизиты.ПолучитьЗначение(Реквизиты.ТекущаяСтрока());
    Запрос=СоздатьОбъект("Запрос");
    ТекстЗапроса="ЗапЭлемент = Справочник."+ТекЭлемент+".ТекущийЭлемент;
    |ЗапРеквизит = Справочник."+ТекЭлемент+"."+ТекРеквизит+";
    |Группировка ЗапЭлемент без упорядочивания;";
    Если Запрос.Выполнить(ТекстЗапроса)=0 Тогда
        Сообщить("Не выполнился запрос!");
        Возврат;
    КонецЕсли;
    Состояние("Проверка соответствия");
    Пока Запрос.Группировка(1)=1 Цикл
        ТекЗначение=СокрП(Запрос.ЗапРеквизит);
        Если РегистрСимволов=1 Тогда
            //1-учитывать регистр
            ТекРезультатПроверки=ПроверкаСтроки(ТекЗначение);
        Иначе
            //0- не учитывать регистр
            ТекРезультатПроверки=ПроверкаСтроки(Врег(ТекЗначение));
        КонецЕсли;
        Если ТекРезультатПроверки = 1 Тогда
            Список.НоваяСтрока();
            Список.Элемент=Запрос.ЗапЭлемент;
            Список.Реквизит=ТекЗначение;
        КонецЕсли;
    КонецЦикла;
    Запрос=0;
КонецПроцедуры
//________________________________________________________
Процедура приОткрытии()
    // Пример строки для фильтрации
    Для х=1 По Метаданные.Справочник() Цикл // перебор справочников
        Справочники.ДобавитьЗначение(МетаДанные.Справочник(х).Идентификатор);
        Если х=1 тогда // Для первого справочника. Остальные при навигации
            Реквизиты.ДобавитьЗначение("Код");
            Реквизиты.ДобавитьЗначение("Наименование");
            Для хх=1 По Метаданные.Справочник(х).Реквизит() Цикл
                Если Метаданные.Справочник(х).Реквизит(хх).Тип="Строка" тогда
                    Если Метаданные.Справочник(х).Реквизит(хх).Длина=0 тогда
                        Продолжить;
                    КонецЕсли;
                    Если Метаданные.Справочник(х).Реквизит(хх).Периодический=1 тогда
                        Продолжить;
                    КонецЕсли;
                    Реквизиты.ДобавитьЗначение(МетаДанные.Справочник(х).Реквизит(хх).Идентификатор );
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЦикла;
    ТекСправочник=Справочники.ПолучитьЗначение(1);
    Форма.ИспользоватьСлой("Источник,Общий");
КонецПроцедуры
//________________________________________________________
Функция Пересчет()
    Если НЕ(ТекСправочник=Справочники.ПолучитьЗначение(Справочники.ТекущаяСтрока())) Тогда
        ТекСправочник=Справочники.ПолучитьЗначение(Справочники.ТекущаяСтрока());
        Реквизиты.УдалитьВсе();
        Если Метаданные.Справочник(ТекСправочник).ДлинаКода>0 Тогда
            Реквизиты.ДобавитьЗначение("Код");
        КонецЕсли;
        Если Метаданные.Справочник(ТекСправочник).ДлинаНаименования>0 Тогда
            Реквизиты.ДобавитьЗначение("Наименование");
        КонецЕсли;
        Для хх=1 По Метаданные.Справочник(ТекСправочник).Реквизит() Цикл
            ТекТип=Метаданные.Справочник(ТекСправочник).Реквизит(хх).Тип;
            Если (ТекТип="Строка") Или (ТекТип="Число") тогда
                Если Метаданные.Справочник(ТекСправочник).Реквизит(хх).Длина=0 тогда
                    Продолжить;
                КонецЕсли;
                Если Метаданные.Справочник(ТекСправочник).Реквизит(хх).Периодический=1 тогда
                    Продолжить;
                КонецЕсли;
                Реквизиты.ДобавитьЗначение(МетаДанные.Справочник(ТекСправочник).Реквизит(хх).Идентификатор);
            КонецЕсли;
        КонецЦикла;
        ТекСправочник=Справочники.ПолучитьЗначение(Справочники.ТекущаяСтрока());
        Реквизиты.Текущаястрока(2);
    КонецЕсли;
КонецФункции
//________________________________________________________
Процедура ПриВыбореЗакладки(ТекНомер)
    Если ТекНомер=1 Тогда
        Форма.ИспользоватьСлой("Источник,Общий");
    Иначе
        Форма.ИспользоватьСлой("Основной,Общий");
    КонецЕсли;
КонецПроцедуры
//________________________________________________________
Форма.ИспользоватьЗакладки(1);
Форма.Закладки.ДобавитьЗначение(1,"Данные");
Форма.Закладки.ДобавитьЗначение(2,"Результат");
Список.НоваяКолонка("Элемент");
Список.НоваяКолонка("Реквизит");

Эту обработку можно загрузить в разделе "Скачать".

 

 

Перепечатка, воспроизведение в любой форме, распространение, в том числе в переводе, любых материалов с сайта www.softpoint.ru возможны только с письменного разрешения компании "СофтПоинт". Это правило действует для всех без исключения случаев, кроме тех, когда в материале прямо указано разрешение на копирование (основание: Закон Российской Федерации "Об авторском праве и смежных правах").