Расширенная функция поиска строк по таблице значений

20.05.25

Разработка - Универсальные функции

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

На текущий момент для поиска по таблице значений есть две функции: "Найти" и  "НайтиСтроки". Первая возвращает строку по значению, указанному в аргументах и именам колонок. Вторая возвращает массив строк по переданной ей структуре, содержащей имена колонок и значения, которые они должны иметь, чтобы попасть в массив результата.

На практике приходится искать по другим критериям – таким, как:

  1. Сравнивать значение в колонки с заданным не только по операнду сравнения, а, например, "больше некоторого значения" или "нахождения в списке"
  2. Сравнивать значения между колонками. Если условие сравнения выполняется, тогда строка должна попадать в результат
  3. Находить колонки, в которых значение значения реквизита равно «чему-то» определенному или больше/меньше «чего-то» определенного
  4. Вычислить функцию от значения в колонке, с чем-то сравнить и если результат будет "чем-то ", тогда включаем строку в массив результата.

Для этих целей служит функция "НайтиСтроки", указанная в этой статье.
Эта функция по аналогии со штатной "НайтиСтроки" также возвращает массив найденных строк.

 

//Осуществляет поиск по таблице значений. Возвращает массив найденных строк
//Параметры:
//	тзТаблица - ТаблицаЗначений - по ней идет поиск
//	Отбор - Строка,Структура,Соответствие - Условия поиска
// 		 - Структура - Выполняет поиск также как и встроеннная функция таблицы значений "НайтиСтроки"
//		 - Соответствие - В соответствии можно указать не только имя колонки, но и имя подчиненного значения в колонке. 
//			Например. Если есть колонка "Номенклатура", тлогда можно производить поиск по родителю этой номенклатуры, указав так "Номенклатура.Родитель"
//			Здесь через пробел также можно писать условия сравнения, например "Номенклатура.Родитель <>". Это означает, что выберуться только те строки, 
//			номенклатура которых не имеет родителя переданного в значении
//		 - Строка - Два варианта: 
//			1) В строке можно тоже указать как путь, по которому происходит сравнение, так и условие сравнения и строковое значение, Например:
//				"Номенклатура.Родитель = Варежки" Тогда функция вернет только те строки, Родитель номенклатуры которых имеет представление "Варежки"
//                2) Указать строковое значение. Тогда найдутся те строки, Значения колонок которых равно указанному
//                3) Написать текст подпрограммы, заключенный в {{ .. }}, которая проверяет значение в колонке. Подпрограмма должна возвращать ИСТИНА, если значение соответствует требуемому. 
//			Чтобы подпрогррамма возвращала ИСТИНУ или ЛОЖЬ в ней необходимо результат привоить переменной "Результат".
//				Пример: "{{Результат =  стрНайти(Строка(Данные),""Агароза"")>0}}". Вернет те строки таблицы,  в которых в значении присутствует "Агароза"
//              4) Написать вызов функции и произвести сравнение результата. Чтобы в качестве аргумента вставить в функцию значение, взятое из определенной колонки таблицы, необходимо Имя получения из колонки заключить в скобки "{}"
//			Пример: Если Отбор = "стрНайти({Номенклатура.Родитель},"виды")>0", тогда функция вернет строки, наименование родителя номенклатуры которого содержит "виды"
//			можно также сравнивать значения дыух колонок, указав в {} имя второй колонки. Например: "Строка({Номенклатура.Родитель}) = Строка({Товар.Родитель})"  - вернет те строки у которых совпадает родитель значения колонок "Номенклатура" и "Товар"
//
Функция НайтиСтроки(тзТаблица,Отбор) Экспорт
	мсвРезультат = НОвый Массив;
	Если ТипЗнч(Отбор) = Тип("Структура") Тогда
		Возврат тзТаблица.НайтиСтроки(Отбор);
	ИначеЕсли ТипЗнч(Отбор) = Тип("Соответствие") Тогда	
		//Необходимо разделить на простые условия и сложные
		сткОтбор = Новый Структура;
		мсвОтбор = Новый Массив;
		Для каждого Элемент Из Отбор Цикл
			Ключ = Элемент.Ключ;
			СтрПодобнаПоРегулярномуВыражению(Ключ,"\w+");
			Если СтрПодобнаПоРегулярномуВыражению(Ключ,"\w+") Тогда
				сткОтбор.Вставить(Элемент.Ключ,Элемент.Значение);
			Иначе
				сткУсловие = РазложитьУсловиеОтбора(Ключ);
				Если Элемент.Значение<>Неопределено Тогда
					сткУсловие.	ПравоеЗначение = Элемент.Значение;
				КонецЕсли;
				мсвОтбор.Добавить(сткУсловие);
			КонецЕсли;
		КонецЦикла;
		
		КоллекцияСтрок = Неопределено;
		Если сткОтбор.Количество()>0 Тогда
			КоллекцияСтрок = тзТаблица.НайтиСтроки(сткОтбор);
		Иначе			
			КоллекцияСтрок = тзТаблица;	
		КонецЕсли;
		
		Если НЕ ЗначениеЗаполнено(КоллекцияСтрок) Тогда
			//Условие уже не выполнилось;
			Возврат мсвРезультат;
		КонецЕсли;
		
		Если мсвОтбор.Количество()=0 Тогда
			Возврат КоллекцияСтрок;
		КонецЕсли;
		
		мсвУсловияОтбора = Новый Массив;
		
		
		Для каждого СтрокаДанных Из КоллекцияСтрок Цикл
			ФлВыполненоУсловие = ИСТИНА;
			Для каждого Элемент Из мсвОтбор Цикл
				Если НЕ ПринадлежитОтбору(СтрокаДанных,Элемент) Тогда
					ФлВыполненоУсловие = ЛОЖЬ;
					Прервать;
				КонецЕсли;
			КонецЦикла; 
			
			Если НЕ ФлВыполненоУсловие Тогда
				Продолжить;
			КонецЕсли;
			
			мсвРезультат.Добавить(СтрокаДанных);
			
		КонецЦикла;
		Возврат мсвРезультат;
	ИначеЕсли ТипЗнч(Отбор) = Тип("Строка") Тогда
		//Проверка на строковое условие сравнения, что СокрЛП(ЗначениеКолонкиТаблицы) = Строка в отборе
		Если Лев(Отбор,2)="{{" И Прав(Отбор,2)="}}" Тогда
			//Значит передана подпрограмма
			ТекстМодуля = Сред(Отбор,3,стрДлина(Отбор)-4);
			Для каждого СтрокаДанных Из тзТаблица Цикл
				Если УсловиеВыполнено(СтрокаДанных,ТекстМодуля) Тогда
					мсвРезультат.Добавить(СтрокаДанных);
				КонецЕсли;
			КонецЦикла;
			Возврат мсвРезультат;
		КонецЕсли;
		
		
		сткУсловиеОтбора = РазложитьУсловиеОтбора(Отбор);
		Для каждого СтрокаДанных Из тзТаблица Цикл
			Если ПринадлежитОтбору(СтрокаДанных,сткУсловиеОтбора) Тогда
				мсвРезультат.Добавить(СтрокаДанных);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	Возврат мсвРезультат;	

КонецФункции // ()


//Преобразует строку условий в Структуру
Функция РазложитьУсловиеОтбора(УсловиеОтбора)
	
	Результат = Новый Структура("ЛеваяЧасть,Операция,ПраваяЧасть,ФункцияЛевойЧасти,ФункцияПравойЧасти,ПравоеЗначение");
	Результат.Вставить("СравниватьКакСтроки",ЛОЖЬ);
	
	Операция = Неопределено;	ПраваяЧасть = "";
	//поищем символы сравнения внутри строки
	РезультатПоиска = СтрНайтиПоРегулярномуВыражению(УсловиеОтбора,"(\s*[>~<=]+\s*)");
	Если РезультатПоиска.НачальнаяПозиция>0 Тогда
		Операция = СокрЛП(РезультатПоиска.Значение); 
		ЛеваяЧасть = Лев(УсловиеОтбора,РезультатПоиска.НачальнаяПозиция-1);
		ПраваяЧасть = Сред(УсловиеОтбора,РезультатПоиска.НачальнаяПозиция + РезультатПоиска.Длина);
	Иначе
		//Символов сравнения нет. Тогда поищем пробелы
		Позиция = стрНайти(УсловиеОтбора," ");
		Если Позиция>0 Тогда
			ЛеваяЧасть = Лев(УсловиеОтбора,Позиция-1);
			Операция = СокрЛП(Сред(УсловиеОтбора,Позиция+1));
			нрегОперация = нрег(Операция);
			Если стрНайти(нрегОперация,"содержит ")=1 Тогда
				ПраваяЧасть = Сред(Операция,10);
				Операция = "СОДЕРЖИТ"	;
			ИначеЕсли стрНайти(нрегОперация,"не содержит ")=1 Тогда
				ПраваяЧасть = Сред(Операция,13);
				Операция = "НЕ СОДЕРЖИТ"	;
			ИначеЕсли стрНайти(нрегОперация,"в списке ")=1 Тогда
				ПраваяЧасть = Сред(Операция,10);
				Операция = "В СПИСКЕ"	;
			ИначеЕсли стрНайти(нрегОперация,"не в списке ")=1 Тогда
				ПраваяЧасть = Сред(Операция,13);
				Операция = "В СПИСКЕ"	;
			КонецЕсли;
		Иначе
			ЛеваяЧасть  =  УсловиеОтбора;
			ПраваяЧасть = "";
		КонецЕсли; 
	КонецЕсли;

	
	РезультатПоиска = СтрНайтиПоРегулярномуВыражению(ЛеваяЧасть,"\{[\w.]+\}");
	Если РезультатПоиска.НачальнаяПозиция>0 Тогда
		Результат.ФункцияЛевойЧасти = ЛеваяЧасть;
		ЛеваяЧасть = Сред(ЛеваяЧасть,РезультатПоиска.НачальнаяПозиция+1,РезультатПоиска.Длина-2);
	КонецЕсли;
	
	Если ПраваяЧасть<>"" Тогда
		РезультатПоиска = СтрНайтиПоРегулярномуВыражению(ПраваяЧасть,"\{[\w.]+\}");
		Если РезультатПоиска.НачальнаяПозиция>0 Тогда
			Результат.ФункцияПравойЧасти = ПраваяЧасть;
			ПраваяЧасть = Сред(ПраваяЧасть,РезультатПоиска.НачальнаяПозиция+1,РезультатПоиска.Длина-2);
		Иначе
			//Определим, вдруг справа стоит функция
			РезультатПоиска = СтрНайтиПоРегулярномуВыражению(ПраваяЧасть,"\{[\w.]+\(.*\)\}"); 
			Если РезультатПоиска.НачальнаяПозиция>0 Тогда
				Результат.ФункцияПравойЧасти = Сред(ПраваяЧасть,РезультатПоиска.НачальнаяПозиция+1,РезультатПоиска.Длина-2);	
			Иначе
				//Посмотрим, вдруг правое значение представлено списком
				РезультатПоиска = СтрНайтиПоРегулярномуВыражению(ПраваяЧасть,"\{[\w.]+\(.*\)\}"); 
				Результат.ПравоеЗначение = ПраваяЧасть;
			КонецЕсли;
			
			ПраваяЧасть = "";
		КонецЕсли;
	КонецЕсли;
	
	
	Если НЕ ЗначениеЗаполнено(Операция) Тогда
		Операция = "=";
	КонецЕсли;
	
	Результат.ЛеваяЧасть = ЛеваяЧасть;
	Результат.ПраваяЧасть = ПраваяЧасть;
	Результат.Операция = Операция;
		
	
	Возврат Результат;
КонецФункции // ()


//Проверяет, что данные удовлетворяют условию Отбора
Функция ПринадлежитОтбору(Данные,Знач УсловиеОтбора) Экспорт
	
	Если ТипЗнч(УсловиеОтбора)=Тип("Структура") Тогда
		сткЧастиУсловия = УсловиеОтбора;
	Иначе
		сткЧастиУсловия = РазложитьУсловиеОтбора(УсловиеОтбора);	
	КонецЕсли;
	
	
	ЛевоеЗначение = ПолучитьРеквизит(Данные,сткЧастиУсловия.ЛеваяЧасть);
	Если ЗначениеЗаполнено(сткЧастиУсловия.ФункцияЛевойЧасти) Тогда
		АргументЗамены = "{"+сткЧастиУсловия.ЛеваяЧасть+"}";
		Если стрНайти(сткЧастиУсловия.ФункцияЛевойЧасти,АргументЗамены)>0 Тогда
			Выражение = стрЗаменить(сткЧастиУсловия.ФункцияЛевойЧасти,АргументЗамены,"ЛевоеЗначение");
			ЛевоеЗначение = Вычислить(Выражение);
		Иначе	
			ЛевоеЗначение = Вычислить(сткЧастиУсловия.ФункцияЛевойЧасти+"(ЛевоеЗначение)");
		КонецЕсли;
	КонецЕсли;
	
	
	Если ЗначениеЗаполнено(сткЧастиУсловия.ПраваяЧасть) Тогда
		ПравоеЗначение = ПолучитьРеквизит(Данные,сткЧастиУсловия.ПраваяЧасть); 
		Если ЗначениеЗаполнено(сткЧастиУсловия.ФункцияПравойЧасти) Тогда
			АргументЗамены = "{"+сткЧастиУсловия.ПраваяЧасть+"}";
			Если стрНайти(сткЧастиУсловия.ФункцияПравойЧасти,АргументЗамены)>0 Тогда
				Выражение = стрЗаменить(сткЧастиУсловия.ФункцияПравойЧасти,АргументЗамены,"ПравоеЗначение");
				ПравоеЗначение = Вычислить(Выражение);
			Иначе
				ПравоеЗначение = Вычислить(сткЧастиУсловия.ФункцияПравойЧасти+"(ПравоеЗначение)");	
			КонецЕсли;
		КонецЕсли;
	ИначеЕсли ЗначениеЗаполнено(сткЧастиУсловия.ФункцияПравойЧасти) Тогда	
		ПравоеЗначение = Вычислить(сткЧастиУсловия.ФункцияПравойЧасти);
	Иначе
		ПравоеЗначение = сткЧастиУсловия.ПравоеЗначение;	
	КонецЕсли;
	
	
	УсловиеСравнения = ВРЕГ(сткЧастиУсловия.Операция);	
	Если ПравоеЗначение<>Неопределено Тогда
		Если ТипЗнч(ПравоеЗначение)<>ТипЗнч(ЛевоеЗначение) Тогда
			Если ТипЗнч(ПравоеЗначение)<>Тип("Массив") И ТипЗнч(ПравоеЗначение)<>Тип("СписокЗначений") Тогда
				ЛевоеЗначение = Строка(ЛевоеЗначение);
				ПравоеЗначение = Строка(ПравоеЗначение);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	
	Если УсловиеСравнения="=" И ЛевоеЗначение = ПравоеЗначение Тогда
		Возврат ИСТИНА;
	ИначеЕсли УсловиеСравнения="<>" И ЛевоеЗначение <> ПравоеЗначение Тогда
		Возврат ИСТИНА;
	ИначеЕсли УсловиеСравнения=">" И ЛевоеЗначение > ПравоеЗначение Тогда
		Возврат ИСТИНА;
	ИначеЕсли УсловиеСравнения=">=" И ЛевоеЗначение >= ПравоеЗначение Тогда
		Возврат ИСТИНА;
	ИначеЕсли УсловиеСравнения="<" И ЛевоеЗначение < ПравоеЗначение Тогда
		Возврат ИСТИНА;
	ИначеЕсли УсловиеСравнения="<=" И ЛевоеЗначение <= ПравоеЗначение Тогда
		Возврат ИСТИНА;
	ИначеЕсли (УсловиеСравнения)="В СПИСКЕ" Тогда
		Если ТипЗнч(ПравоеЗначение)=Тип("Массив") Тогда
			Возврат ПравоеЗначение.Найти(ЛевоеЗначение)<>Неопределено;
		ИначеЕсли ТипЗнч(ПравоеЗначение)=Тип("СписокЗначений") Тогда	
			Возврат ПравоеЗначение.НайтиПоЗначению(ЛевоеЗначение)<>Неопределено;
		КонецЕсли;
	ИначеЕсли (УсловиеСравнения)="НЕ В СПИСКЕ" Тогда	
		Если ТипЗнч(ПравоеЗначение)=Тип("Массив") Тогда
			Возврат ПравоеЗначение.Найти(ЛевоеЗначение)=Неопределено;
		ИначеЕсли ТипЗнч(ПравоеЗначение)=Тип("СписокЗначений") Тогда	
			Возврат ПравоеЗначение.НайтиПоЗначению(ЛевоеЗначение)=Неопределено;
		КонецЕсли;	
	ИначеЕсли (УсловиеСравнения)="ЗАПОЛНЕНО"  Тогда	
		Возврат  ЗначениеЗаполнено(ЛевоеЗначение);
	ИначеЕсли (УсловиеСравнения)="НЕ ЗАПОЛНЕНО" Тогда
		Возврат НЕ  ЗначениеЗаполнено(ЛевоеЗначение);
	ИначеЕсли (УсловиеСравнения)="~"  Тогда	
		Возврат СтрПодобнаПоРегулярномуВыражению(ЛевоеЗначение,ПравоеЗначение);
	ИначеЕсли (УсловиеСравнения)="СОДЕРЖИТ"  Тогда	
		стрТекущееЗначение = нрег(Строка(ЛевоеЗначение));
		стрЗначениеСравнения = нрег(Строка(ПравоеЗначение));
		Возврат стрНайти(стрТекущееЗначение,стрЗначениеСравнения)>0;
	ИначеЕсли (УсловиеСравнения)="НЕ СОДЕРЖИТ"  Тогда	
		стрТекущееЗначение = нрег(Строка(ЛевоеЗначение));
		стрЗначениеСравнения = нрег(Строка(ПравоеЗначение));
		Возврат стрНайти(стрТекущееЗначение,стрЗначениеСравнения)=0;
	КонецЕсли;
	Возврат ЛОЖЬ;

КонецФункции // ()





//Возвращает значение реквизита из данных по пути
Функция ПолучитьРеквизит(Данные,Знач ИмяРеквизита,ЗначениеПоУмолчанию = Неопределено) Экспорт
	Если НЕ ЗначениеЗаполнено(ИмяРеквизита) Тогда
		Возврат ЗначениеПоУмолчанию;
	КонецЕсли; 
	
	Позиция = стрНайти(ИмяРеквизита,".");
	СледующееИмяРеквизита = Неопределено;
	Если Позиция>0 Тогда
		СледующееИмяРеквизита = Сред(ИмяРеквизита,Позиция+1);
		ИмяРеквизита = Лев(ИмяРеквизита,Позиция-1);
	КонецЕсли;
	
			
		
	сткЗначения = Новый Структура(ИмяРеквизита);
	ЗаполнитьЗначенияСвойств(сткЗначения,Данные);
	Если сткЗначения[ИмяРеквизита] = Неопределено Тогда
		Возврат ЗначениеПоУмолчанию;
	КонецЕсли;
		
	Результат =  сткЗначения[ИмяРеквизита];

	Если ЗначениеЗаполнено(СледующееИмяРеквизита) Тогда
		Возврат ПолучитьРеквизит(Результат,СледующееИмяРеквизита,ЗначениеПоУмолчанию);
	КонецЕсли;
	Возврат Результат;
КонецФункции // ()

//Выполняет текст 
Функция УсловиеВыполнено(Данные,___Условие,Ошибка = "") Экспорт
	___ТекстМодуля = "";
	Параметры = Неопределено;
	Результат = ЛОЖЬ;
	
	Если ТипЗнч(___Условие)=Тип("Строка") Тогда
		___ТекстМодуля = ___Условие;	
	ИначеЕсли ТипЗнч(___Условие)=Тип("Структура") Тогда	
		___Условие.Свойство("ТекстМодуля",___ТекстМодуля);
		___Условие.Свойство("Параметры",Параметры);
	Иначе
		Возврат ЛОЖЬ;
	КонецЕсли; 
	
	Если ЗначениеЗаполнено(___ТекстМодуля) Тогда
		Попытка
			Выполнить(___ТекстМодуля);
		Исключение
			Ошибка = ОписаниеОшибки();		
			Результат = ЛОЖЬ;
		КонецПопытки;
	КонецЕсли;
	
	Возврат Результат;	

КонецФункции // ()

 

Первый аргумент: таблица значений, в которой мы ищем строки.

Второй аргумент "Отбор": это условие, по которому происходит отбор.

 

Если Отбор - структура, тогда функция работает также, как штатная.

 

Начну с описания случая, когда Отбор - строка, т.к. его понимание приведет к пониманию того, как пользоваться случаем, когда "Отбор" - соответствие.

Пусть Таблица, по которой идет поиск имеет три колонки "Номенклатура", "Товар", "Количество", "Цена", "Сумма".

  • Колонки "Номенклатура" и "Товар" - ссылки на справочник "Номенклатура". При этом не всегда значение в колонке "Товар" совпадает со значением в колонке "Номенклатура".
  • Колонки "Количество", "Цена", "Сумма" - числовые.

Самый простой случай - это когда мы задаем в "Отборе" программный код, заключенный между "{{" и "}}". Внутри этого кода можно обратиться к переменной "Данные", которая будет содержать строку таблицы, а в переменную "Результат" необходимо занести ИСТИНА или ЛОЖЬ, как результат выполнения. Если "Результат" будет ИСТИНА, тогда строка таблицы попадет в массив найденных строк.

Например, если аргумент "Отбор" указан как:

Отбор = "{{Если Строка(Данные.Номенклатура)  = Строка(Данные.Товар) Тогда Результат = ИСТИНА Иначе Результат = ЛОЖЬ}}";

В этом случае функция вернет массив строк, в которых представление значения в колонках "Товар" и "Номенклатура" одинаковые.


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

Отбор = "ЛевоеЗначение ОперандСравнения [ПравоеЗначение]";

Где:

ОперандСравнения – одно из возможных значений "=", ">", "<", ">=", "<=", "В СПИСКЕ", "НЕ В СПИСКЕ", "ЗАПОЛНЕНО", "НЕ ЗАПОЛНЕНО", "СОДЕРЖИТ", "НЕ СОДЕРЖИТ", "~"

  • Операнд "~" означает, что надо проверить правое значение на совпадение с регулярным выражением, указанным в правой части.
  • При операнде "ЗАПОЛНЕНО" и "НЕ ЗАПОЛНЕНО" правая часть не должна иметь ничего, т.к. эти операнды проверяют левое значение на «заполненность».
  • Операнды: "СОДЕРЖИТ", "НЕ СОДЕРЖИТ" проверяют вхождение правого значения в левом.

ЛевоеЗначение – это значение, полученное из колонки и каким-то образом обработанное. Чтобы получить "Левое значение" из колонки можно:

  1. Указать имя колонки напрямую, например: "Товар" или "Номенклатура". Тогда в качестве Левого значения будет взято значение этой колонки.
  2. Указать путь имени реквизита значения колонки через символ точки. Пример: "Номенклатура.Родитель.Наименование". В этом случае в качестве левого значения будет наименование родителя номенклатуры.
  3. Указать путь имени реквизита и функцию его модификации. При этом чтобы значение, взятое по пути, попало аргументом в функцию, необходимо путь заключить в скобки "{}".
    Пример: "Лев({Номенклатура.Родитель},5)". В качестве левого значения будет взято 5 символов из представления "родителя" значения колонки "Номенклатуры"

ПравоеЗначение можно задать одним из следующих образов:

  • Взять конкретную строку, указанную после операндов. В этом случае операнды: "В СПИСКЕ", "НЕ В СПИСКЕ", "СОДЕРЖИТ", "НЕ СОДЕРЖИТ" должны быть отделены пробелом от строки операнда.
  • Использовать функцию или значение, взятое из определенной колонки по аналогии с п.3. Пример: "Лев(Лев({Товар.Родитель},5))". В этом примере в качестве правого значения возьмется первые 5 символов представления значения родителя.
  • Использовать функцию без вызова колонки. Тогда функцию нужно экранировать скобками {}, иначе она воспримется как строка символов. Пример: {Число(4)}

Следует отметить, что если тип левого значения не совпадает с типом правого, тогда сравнение происходит "строковое". Оба значения приводятся перед сравнением к строке, за исключением случая, когда правое значение - массив или список значений.

 

А теперь примеры.

Пример 1. Найдем колонки, в которых значение колонки "Цена" равна значению в колонке "Сумма":

Отбор = "Цена = {Сумма}";
мсвСтроки = НайтиСтроки(ТЗ,Отбор);

 
Пример 2. Найдем колонки, у которых цена больше 2.

Отбор = "Цена>{Число(2)}";

Здесь мы привели "2" к числу. Если этого не делать, а написать так "Цена> 2", тогда та цена, равная 10 не попадет, т.к. "2" функция посчитает, что это строка и приведет 10 к строке "10". Строка "10" меньше строки "2", т.к. символ "1" идет перед символом "2".


Пример 3. Найдем колонки, у которых наименование родителя значения колонки "Номенклатура" содержат 5 первых символов наименования родителя значения из колонки "Товар":

Отбор = "{Номенклатура.Родитель} СОДЕРЖИТ Лев({Товар.Родитель},5)";


Пример 4. Найдем строки, в которых представление значения колонки "Номенклатура" вначале содержит любые символы, а в конце обязательно цифры:

Отбор = "{Номенклатура} ~ .+\d+";

Здесь мы прибегли к использованию регулярных выражений.


Теперь можно перейти к случаю, когда Отбор  - соответствие.
Ключ каждого элемента соответствия это по сути строка условия, описанного выше. Только вместо правого значения можно использовать значение элемента соответствия.
Это удобно сделать, когда Левое значение надо проверить на вхождение в массив или список значений с использованием операндов "В СПИСКЕ"  или "НЕ В СПИСКЕ" или не приводить значение из строки в Число, как это было в примере 2. Все элементы соответствия объединяются по условию "И".

Пример 5. Необходимо найти те строки, у которых значение в колонке Сумма больше 5.

Отбор = Новый Соответствие;
Отбор.Вставить("Сумма >",5);
мсвСтроки = НайтиСтроки(ТЗ,Отбор);


Пример 6. Найти строки, у которых не заполнена цена:

Отбор.Вставить("Цена не заполнено");


Пример 7. Найти строки, у которых представление родителя номенклатуры находится в некотором списке, состоящем из "Пирожки" и "Тарелки". При этом реквизит номенклатуры "ТипНомеклатуры"   -  не является услугой и при этом номенклатура не является группой.

мсвСписок = Новый Массив; //Здесь сам список 
мсвСписок.Добавить("Пирожки");
мсвСписок.Добавить("Тарелки");

Отбор = Новый Соответствие;
Отбор.Вставить("Строка({Номенклатура.Родитель}) В СПИСКЕ",мсвСписок); //Приводим "Родителя к представлению через функцию "Строка(...)""
Отбор.Вставить("Номенклатура.ТипНоменклатуры <>",Перечисления.ТипыНоменклатуры.Услуга); //Сравниваем с услугой
Отбор.Вставить("Номенклатура.ЭтоГруппа",ЛОЖЬ); //Операнд "=" можно опускать
мсвСтроки = НайтиСтроки(ТЗ,Отбор);

 

 

Вступайте в нашу телеграмм-группу Инфостарт

ТаблицаЗначений Поиск НайтиСтроки Отбор

См. также

Загрузка и выгрузка в Excel Универсальные функции Программист 1С:Предприятие 8 Россия Бесплатно (free)

Описанный ниже подход позволяет в три шага заполнять формулы в Excel файлы, вне зависимости от ОС сервера (MS Windows Server или Linux). Подход подразумевает отказ от работы с COM-объектом в пользу работы через "объектную модель документа" (DOM).

30.10.2025    3318    Abysswalker    7    

44

Универсальные функции Работа с интерфейсом Программист 1С:Предприятие 8 Бесплатно (free)

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

14.05.2025    6169    DeerCven    15    

57

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

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

21.05.2024    48208    dimanich70    83    

169

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    7257    6    John_d    13    

59

Универсальные функции Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    60141    atdonya    31    

69

Универсальные функции Программист 1С:Предприятие 8 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    9034    ke.92@mail.ru    17    

68
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. user-z99999 77 20.05.25 13:08 Сейчас в теме
Можно таблицу значений закинуть в запрос.
И там искать.
2. chekonst 82 20.05.25 14:04 Сейчас в теме
(1) Я думал над этим. А как быть с регулярными выражениями?
3. Spurk 42 20.05.25 17:00 Сейчас в теме
(2) Одной рукой вы даёте работу с регулярными выражениями, а другой рукой даёте штуки по видов запросов в цикле.
Если я правильно понял, ваш механизм работает перебором строк. Там для каждой строки вы используете отбор и складываете результат в массив, который возвращаете. Исходя из примера, у меня есть таблица значений на 1000 строк, и в отборе мы прописываем:
Отбор.Вставить("Строка({Номенклатура.тип}) Равно",мсвСписок);
Представление не получается просто так, если вы указали например Строка(Номенклатура.Родитель), точнее оно получается после запроса в базу.В данном примере каждый раз при новой строке вы будете гонять в базу данных, получится 1000 запросов - что не хорошо. И это если такой отбор один. В этом случае нужно сразу выгрузить все типы и колонки которые будут участвовать в отборе. Но тогда лучше отобрать сразу запросом.
ef42; BigB; +2 Ответить
4. chekonst 82 20.05.25 17:19 Сейчас в теме
(3) Ну вообще, как известно, нет ничего универсального. Все надо использовать в меру. Может именно для вас этот метод и слишком долгий, а для кого то нет. Интересно сколько времени у вас занял перебор 1000 строк? Час? Пол часа? Минута? Несколько секунд? Если последний ответ Да. Тогда чем же этот метод плох?
7. Spurk 42 21.05.25 03:04 Сейчас в теме
(4) При чём тут долго/плохо? Пользуйтесь на здоровье.
Я сделал замечание про то, что механизм можно использовать, например с работой с строками. Для чего регулярки и есть.
Использовать с ссылочными данными не нужно. Сам подход многократного обращения в базу порицается как самим вендором, так и остальным миром "правильного" it.
Так же, например, при отборе по документСсылка.Контрагент для каждой строки, можно налететь на такую ситуацию, когда вы заблочите документ для других. Про это можно прочитать в книге "Настольная книга 1С:Эксперта по технологическим вопросам".
5. user-z99999 77 20.05.25 17:54 Сейчас в теме
(2) Запрос может только ПОДОБНО (like).
Насколько полно 1с поддерживает like в запросах, не проверял.
6. TMV 3 20.05.25 22:09 Сейчас в теме
выглядит как костыль.
а за имена типа "___ТекстМодуля " надо бить по рукам
8. chekonst 82 21.05.25 09:35 Сейчас в теме
(6) Да,именно костыль, т.к. 1С такое не встроило.
И как вы думаете, почему именно в этом месте вставлено "___", а в других нет? По приколу? Почему это вместо "Выполнить" вставлена отдельная функция? Тоже по приколу?
9. TMV 3 21.05.25 11:00 Сейчас в теме
(8) ничем иным это не объяснить, но можете попробовать
10. chekonst 82 21.05.25 11:14 Сейчас в теме
(9) УсловиеВыполнено() написана отдельной функцией, чтобы "экранировать" текст модуля выполнения от переменных основной, вызывающей функции. Иначе может произойти затирание значений основной функции.
"____" служат для этих же целей. Вы же, как я понял, не любите их применять и даже пытаетесь оторвать мне руки. Вот, надеясь, на эту нелюбовь их и ставят, что другие программисты не затирали такими же именами, но без "___" переменные. Вы на С++ писали? Там такого полно и никто не возмущается и не предлагает оторвать руки.
11. TMV 3 22.05.25 07:18 Сейчас в теме
(10) там нечего экранировать - достаточно давать внятные имена переменным.
Для отправки сообщения требуется регистрация/авторизация