Парсер таблиц по шаблону. Автоматическая корректировка парсера. Сравнение графов

Публикация № 1054367

Разработка - Практика программирования

графы сравнение таблицы программирование алгоритмы v8

Возникла такая задача: нужно нарисовать в макете шаблон таблицы, где расписано какая ячейка за что отвечает, загрузить таблицу из html и сравнить, подходит ли она под шаблон. Если да, то загрузить информацию по правилу из шаблона. Проблема в том, что в html таблица может приходить с ошибками, то есть какие то ячейки совмещены, хотя не должны. Поэтому нужно сделать так, что бы программа понимала, что таблицы похожи и где конкретно ошибки. Соответсвенно, поделил задачу на 3 этапа. 1 - это представление таблицы в виде графа, 2 - сравнение графов, 3 - забор информации. В данной статье пойдет описание пункта 2.

Описание 1го пункта здесь.

Важный момент, это не просто графы, а именно таблицы представленные в виде графа. То есть, считаю что таблицы ориентированы одинаково, исходя из этого, самые верхние левые ячейки таблиц (0 узлы) считаю одинаковыми, и так как нумерация проходит определенным способом, то если таблицы структурно одинаковы, то нумерация каждого из узлов должна совпадать, более того у каждого узла должны быть одинаковые рёбра.

Идея алгоритма очень проста. Граф 1 назову шаблон, граф 2 - граф. Из шаблона и графа построю новый граф. Рассмотрим i-ый узел у шаблона и графа. Берём i+1 узлы и сравниваем. Если рёбра у них одинаковы, то добавляем i узел в новый граф и его рёбра(здесь и далее "добавлять/вставлять рёбра узла" означает "добавлять/вставлять рёбра узла, которые меньше i"). Если отличаются, то есть 3 действия (сортировка по приоритету):

1) ничего не делаю

2) вставляю узел из шаблона

3) вставляю узел из графа.

Для каждого действия рассчитаю i+1 узел шаблона и графа. Для 1 - это просто i+1 узлы. Для 2 i+1 узел графа- это i, у которого часть рёбер убраны, часть увеличено на 1 (подробнее ниже). i+1 шаблона остаётся прежним. Для 3 у i узла шаблона изменятся рёбра, а у i+1 графа остаётся как есть.

Теперь для каждого действия  рассчитываю функцию ошибки между i+1 узлами. Выбираю то действие, у которого функция ошибки меньше. Если есть равенство, то выбираю по приоритету. 

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

функция ВыделитьПервыеЗначенияИзСписка(Список,Предел)
	спис = новый СписокЗначений;
	Для каждого стр из Список цикл
		Если стр.Значение>Предел тогда
			Прервать;
		КонецЕсли;
		спис.Добавить(стр.Значение);
	КонецЦикла;
	возврат спис;
КонецФункции

функция КоэфициентВхожденияСписка1ВСписке2(список1,список2)
	
	//критерий. максимум насколько одна вершина входит во вторую
	Если типЗнч(список1) = тип("Массив") тогда
		_список1 = новый СписокЗначений;
		_список1.ЗагрузитьЗначения(список1);
	иначе
		_список1 = список1;
	КонецЕсли;
	
	Если типЗнч(список2) = тип("Массив") тогда
		_список2 = новый СписокЗначений;
		_список2.ЗагрузитьЗначения(список2);
	иначе
		_список2 = список2;
	КонецЕсли;
	
	Вхождений1 = 0;
	Для каждого стр из _список1 цикл
		Если _список2.найтиПоЗначению(стр.Значение)<> Неопределено тогда
			Вхождений1 = Вхождений1+1;
		КонецЕсли;
	КонецЦикла;
	
    //0 - всё входит, 1 - ничего
	Если _список1.Количество() = 0 или _список2.Количество() = 0 тогда
		возврат 1;
	КонецЕсли;
	
	КоэффициентВхождений = 1-окр(Вхождений1/_список1.Количество(),2);//макс(окр(Вхождений1/_список1.Количество(),2),окр(Вхождений2/_список2.Количество(),2));
	возврат КоэффициентВхождений; 
КонецФункции

функция ВычислитьКоличествоОшибок(список1,список2)
	
	//критерий. насколько отличаются списке в абсолютном значении
	Если типЗнч(список1) = тип("Массив") тогда
		_список1 = новый СписокЗначений;
		_список1.ЗагрузитьЗначения(список1);
	иначе
		_список1 = список1;
	КонецЕсли;
	
	Если типЗнч(список2) = тип("Массив") тогда
		_список2 = новый СписокЗначений;
		_список2.ЗагрузитьЗначения(список2);
	иначе
		_список2 = список2;
	КонецЕсли;
	
	
	если _список1.Количество()< _список2.Количество() тогда
		расСпис = _список1;
		СЧемСравнивать = _список2; 
	иначе
		расСпис = _список2;
		СЧемСравнивать = _список1; 
	КонецЕсли;
	КоэффициентВхождений = 0;
	Для каждого стр из расСпис цикл
		Если СЧемСравнивать.найтиПоЗначению(стр.Значение)<> Неопределено тогда
			КоэффициентВхождений = КоэффициентВхождений+1;
		КонецЕсли;
	КонецЦикла;	
	
	если КоэффициентВхождений = _список1.Количество() и КоэффициентВхождений = _список2.Количество() тогда
		//это абсолютно одинаковые узлы
		возврат 0;
	иначе
		возврат ?(КоэффициентВхождений = 0,100,1/КоэффициентВхождений);
	КонецЕсли;
	
КонецФункции

Процедура ДобавитьСвязиВпрошлыеУзлыСТекущим(Куда, что, Индекс)
	Для каждого узел из что цикл
		если Куда[узел.значение].найтиПоЗначению(Индекс) = Неопределено тогда
			Куда[узел.значение].Добавить(Индекс);
			Куда[узел.значение].СортироватьПоЗначению();
		КонецЕсли;
	КонецЦикла;    	
КонецПроцедуры

Процедура Прибавить1КНомеруУзла(МассивУзлов, Индекс)
	Для инт = 0 по МассивУзлов.Количество()-1 цикл
		НовСписокКуда = новый СписокЗначений;
		Для каждого УзелГрафа из МассивУзлов[инт] цикл
			Если УзелГрафа.Значение>=Индекс тогда
				НовСписокКуда.Добавить(УзелГрафа.Значение + 1);
			иначе
				НовСписокКуда.Добавить(УзелГрафа.Значение);
			КонецЕсли;
		КонецЦикла;
		МассивУзлов[инт] = НовСписокКуда;
	КонецЦикла;    	
КонецПроцедуры

функция РассчитатьСледующийУзел(ИзЧегоСчитать,ВставляемыйУзел,Индекс,УзлыОставлять=Неопределено)
	//если в ВставляемыйУзел есть связь с узлом, которая есть в ИзЧегоСчитать, то её надо поменять на индекс
	//типа разбиваем связь
	если УзлыОставлять = Неопределено тогда
		УзлыОставлять = новый СписокЗначений;
	КонецЕсли;
	РассчетныйСледующийШаблона = новый СписокЗначений;
	Для каждого узел из ИзЧегоСчитать цикл
		Если ВставляемыйУзел.найтиПоЗначению(узел.Значение) <> Неопределено и УзлыОставлять.найтиПоЗначению(узел.Значение) = Неопределено тогда
			если РассчетныйСледующийШаблона.найтиПоЗначению(Индекс) = Неопределено тогда
				РассчетныйСледующийШаблона.Добавить(Индекс);	
			КонецЕсли;
		иначеесли узел.Значение>Индекс тогда
			РассчетныйСледующийШаблона.Добавить(Узел.Значение+1);	
		иначе
			РассчетныйСледующийШаблона.Добавить(Узел.Значение);	
		КонецЕсли;
	КонецЦикла;
	возврат РассчетныйСледующийШаблона;
КонецФункции

Процедура  ВставитьНовыйУзелВГраф(НовыйГраф,Индекс,НовыеУзлы,ВставляемыеУзлы,Источник,ДругойГраф,АтрибутыДругойГраф)
	НовыйГраф.Вставить(Индекс,НовыеУзлы);			
	ДобавитьСвязиВпрошлыеУзлыСТекущим(НовыйГраф, НовыеУзлы,Индекс);
	Прибавить1КНомеруУзла(ДругойГраф,Индекс);
	ДругойГраф.Вставить(Индекс,новый СписокЗначений);
	АтрибутыДругойГраф.Вставить(индекс);
	нов = ВставляемыеУзлы.Добавить();
	нов.Источник = Источник;
	нов.Индекс = Индекс;
КонецПроцедуры

Процедура ОбъединитьРёбраУзла(ВставляемыеРёбра,УзлыГраф,УзлыШаблон,НовыйГраф,Индекс)
	СписокВставляемыРёбер = ВставляемыеРёбра.Получить(Индекс);
	Если СписокВставляемыРёбер = Неопределено тогда
		СписокВставляемыРёбер = новый СписокЗначений;
	КонецЕсли;
	
	НовыеУзлы = новый СписокЗначений;
	Для каждого стр из УзлыГраф цикл 					
		если НовыеУзлы.найтиПоЗначению(стр.значение) = Неопределено тогда
			НовыеУзлы.Добавить(стр.значение);
		КонецЕсли;
		Если УзлыШаблон.найтиПоЗначению(стр.значение) = Неопределено тогда
			СписокВставляемыРёбер.Добавить(стр.значение);
			найд = ВставляемыеРёбра.Получить(стр.значение);
			Если найд = Неопределено тогда
				найд = новый СписокЗначений;
			КонецЕсли;
			найд.Добавить(Индекс);			
			ВставляемыеРёбра.Вставить(стр.значение,найд);
		КонецЕсли;
	КонецЦикла;
	Для каждого стр из УзлыШаблон цикл 					
		если НовыеУзлы.найтиПоЗначению(стр.значение) = Неопределено тогда
			НовыеУзлы.Добавить(стр.значение);
		КонецЕсли;
		Если УзлыГраф.найтиПоЗначению(стр.значение) = Неопределено тогда
			СписокВставляемыРёбер.Добавить(стр.значение);
			найд = ВставляемыеРёбра.Получить(стр.значение);
			Если найд = Неопределено тогда
				найд = новый СписокЗначений;
			КонецЕсли;
			найд.Добавить(Индекс);
			ВставляемыеРёбра.Вставить(стр.значение,найд);
		КонецЕсли; 					
	КонецЦикла;
	НовыйГраф.Вставить(Индекс,НовыеУзлы);
	ДобавитьСвязиВпрошлыеУзлыСТекущим(НовыйГраф, НовыеУзлы,Индекс);
	ВставляемыеРёбра.Вставить(Индекс,СписокВставляемыРёбер);
КонецПроцедуры

функция РассчитатьОшибкиПриВставкеУзла(Откуда,ИндексОткуда,Индекс,Куда,ВставляемыйУзел)
	РассчетныйСледующийОткуда = Откуда[ИндексОткуда];
	РассчетныйСледующийКуда = РассчитатьСледующийУзел(Куда[Индекс],ВставляемыйУзел,Индекс);
	количествоОшибок = ВычислитьКоличествоОшибок(РассчетныйСледующийКуда,РассчетныйСледующийОткуда);
	//расмматриваются все возможные сочетания (без учета места)
	Для инт=0 по ВставляемыйУзел.Количество()-1 цикл
		УзлыОставлять = новый СписокЗначений;
		УзлыОставлять.Добавить(ВставляемыйУзел[инт].Значение);
		РассчетныйСледующийКуда = РассчитатьСледующийУзел(Куда[Индекс],ВставляемыйУзел,Индекс,УзлыОставлять);
		количествоОшибок = мин(ВычислитьКоличествоОшибок(РассчетныйСледующийКуда,РассчетныйСледующийОткуда),количествоОшибок);
		
		Для йцу = инт+1 по  ВставляемыйУзел.Количество()-1 цикл
			УзлыОставлять.Добавить(ВставляемыйУзел[йцу].Значение);
			РассчетныйСледующийКуда = РассчитатьСледующийУзел(Куда[Индекс],ВставляемыйУзел,Индекс,УзлыОставлять);
			количествоОшибок = мин(количествоОшибок,ВычислитьКоличествоОшибок(РассчетныйСледующийКуда,РассчетныйСледующийОткуда));
		КонецЦикла;
	КонецЦикла;
	возврат КоличествоОшибок;
КонецФункции

&НаСервере
процедура ЗаполнитьНовыйГраф(НовыйГраф,Шаблон,Граф,ВставляемыеУзлы,ВставляемыеРёбра,АтрибутыШаблона,АтрибутыГрафа)
	МаксРазмер = макс(Шаблон.Количество(), Граф.Количество());
	Индекс=0;
	Пока Индекс<=МаксРазмер-1 цикл  		
		//рассматриваем только узлы, которые меньше текущего индекса
		если Шаблон.ВГраница()<Индекс и Граф.ВГраница()<Индекс тогда
			Прервать;
		иначеесли Шаблон.ВГраница()<Индекс тогда
			НовыеУзлы = ВыделитьПервыеЗначенияИзСписка(Граф[Индекс],Индекс); 
			ВставитьНовыйУзелВГраф(НовыйГраф,Индекс,НовыеУзлы,ВставляемыеУзлы,"Граф",Шаблон,АтрибутыШаблона);
			Индекс = Индекс + 1;
			Продолжить;
		иначеесли Граф.ВГраница()<Индекс тогда
			НовыеУзлы = ВыделитьПервыеЗначенияИзСписка(Шаблон[Индекс],Индекс); 
			ВставитьНовыйУзелВГраф(НовыйГраф,Индекс,НовыеУзлы,ВставляемыеУзлы,"Шаблон",Граф,АтрибутыГрафа);
			Индекс = Индекс + 1;
			Продолжить;
		КонецЕсли;
		
		УзлыШаблон = Шаблон[Индекс];
		УзлыГраф = граф[Индекс];
		
		если строка(УзлыГраф) = строка(УзлыШаблон) тогда
			//вставим рёбра в прошлые узлы
			Узлы = ВыделитьПервыеЗначенияИзСписка(УзлыШаблон,Индекс); 
			НовыйГраф.Вставить(Индекс,Узлы);	
			ДобавитьСвязиВпрошлыеУзлыСТекущим(НовыйГраф, Узлы,Индекс);
		иначе
			//рассмотрим 3 действия
			//1)объединим рёбра узлов графа и шаблона
			//2)Добавим узел шаблона
			//3)Добавим узел графа
			//Сравним следующие узлы в каждом из случаев. Выберу тот случай, в котором ошибка наименьше.
			//если это последняя узел для одной, то сравниваем следующую с ней.
			//если обе последние, то соединяем
			если Индекс=Шаблон.ВГраница() и Граф.ВГраница()=Индекс тогда
				УзлыГраф = ВыделитьПервыеЗначенияИзСписка(УзлыГраф,Индекс);
				УзлыШаблон = ВыделитьПервыеЗначенияИзСписка(УзлыШаблон,Индекс);				
				ОбъединитьРёбраУзла(ВставляемыеРёбра,УзлыГраф,УзлыШаблон,НовыйГраф,Индекс);
			иначе
				ИндексШаблон = ?(Индекс=Шаблон.ВГраница(),Индекс,Индекс+1);
				ИндексГраф = ?(Индекс=Граф.ВГраница(),Индекс,Индекс+1);
				//1
				СледующийУзелГраф = Граф[ИндексГраф]; 
				СледующийУзелШаблон = Шаблон[ИндексШаблон];
				количествоОшибокНичего = ВычислитьКоличествоОшибок(СледующийУзелГраф,СледующийУзелШаблон);
				//бывает ситуация когда ошибка влияет на рёбра узла. К примеру, рассматриваем 9 узел, ошибка в 11
				//рёбра 9 {12,13,14}. Корректнее ничего не делать, 11 узел добавляю, все корректно.
				//НО, если просто смотреть, то рёбра на текущий момент у одного графа {13,14,15} а у второго {12,13,14}
				//тогда программа решает что выгоднее производить другое действия.
				//поэтому имеет смысл рассматривать варианты +1 к следующим за индексом узлам. 				
				РассчетныйСледующийШаблона = РассчитатьСледующийУзел(СледующийУзелШаблон,новый СписокЗначений,Индекс,новый СписокЗначений);
				РассчетныйСледующийГраф = РассчитатьСледующийУзел(СледующийУзелГраф ,новый СписокЗначений,Индекс,новый СписокЗначений);
				количествоОшибокНичего = мин(количествоОшибокНичего,ВычислитьКоличествоОшибок(СледующийУзелГраф,РассчетныйСледующийШаблона),ВычислитьКоличествоОшибок(СледующийУзелШаблон,РассчетныйСледующийГраф));
				//2  				
				//при вставке узла, есть вариант когда рёбра расчётного следующего разрушаются, а могут и не разрушаться
				//просмотрю все варианты и выберу наименьшую ошибку
				ВставляемыйУзелГраф = ВыделитьПервыеЗначенияИзСписка(Граф[Индекс],Индекс);
				КоличествоОшибокВставитьГраф = РассчитатьОшибкиПриВставкеУзла(Граф,ИндексГраф,Индекс,Шаблон,ВставляемыйУзелГраф);
				//3
				ВставляемыйУзелШаблон = ВыделитьПервыеЗначенияИзСписка(Шаблон[Индекс],Индекс);
				количествоОшибокВставитьШаблон = РассчитатьОшибкиПриВставкеУзла(Шаблон,ИндексШаблон,Индекс,граф,ВставляемыйУзелШаблон);
				
				МинОшибка = мин(количествоОшибокНичего ,количествоОшибокВставитьГраф,количествоОшибокВставитьШаблон);
				
				НичегоНеДелать = МинОшибка =  количествоОшибокНичего;
				ДобавитьУзелИзГрафа = МинОшибка =  количествоОшибокВставитьГраф; 
				ДобавитьУзелИзШаблона = МинОшибка =  количествоОшибокВставитьШаблон; 
				
				//также конкретно следующий узел может быть ошибочным, поэтому сравнение следующих узлов может выдать некорректное действие.
				//Попробую вставить не текущий узел, а следующий, заодно рассчитать послеследующий узел и ошибки в нём
				//Если ошибка меньше чем текущая ошибка вставки, то выгоднее ничего не делать.
				Если  КоличествоОшибокВставитьГраф<>0 и количествоОшибокВставитьШаблон<>0 тогда
					если ДобавитьУзелИзШаблона и ИндексШаблон<Шаблон.ВГраница()и Индекс<Граф.ВГраница() тогда
						КоличествоОшибокВставитьСледующий = ВычислитьКоличествоОшибок(РассчитатьСледующийУзел(Граф[Индекс+1],ВыделитьПервыеЗначенияИзСписка(Шаблон[Индекс+1],Индекс+1),Индекс+1),Шаблон[ИндексШаблон+1]);
						если  КоличествоОшибокВставитьСледующий< количествоОшибокВставитьШаблон тогда
							НичегоНеДелать = истина;
						КонецЕсли;
					КонецЕсли; 
					если ДобавитьУзелИзГрафа и ИндексГраф<Граф.ВГраница() и Индекс<Шаблон.ВГраница() тогда
						КоличествоОшибокВставитьСледующий = ВычислитьКоличествоОшибок(РассчитатьСледующийУзел(Шаблон[Индекс+1],ВыделитьПервыеЗначенияИзСписка(Граф[Индекс+1],Индекс+1),Индекс+1),Граф[ИндексГраф+1]);
						если  КоличествоОшибокВставитьСледующий< КоличествоОшибокВставитьГраф тогда
							НичегоНеДелать = истина;
						КонецЕсли;
					КонецЕсли;
				КонецЕсли;
				
				Если НичегоНеДелать тогда
					//1) объединяем
					//надо запомнить какие узлы откуда были добавлены
					ОбъединитьРёбраУзла(ВставляемыеРёбра,ВставляемыйУзелГраф,ВставляемыйУзелШаблон,НовыйГраф,Индекс);
				ИначеЕсли ДобавитьУзелИзШаблона тогда 
					//2)Добавим узел Шаблона
					НовыеУзлы = новый СписокЗначений;
					НовыеУзлы.ЗагрузитьЗначения(ВставляемыйУзелШаблон.ВыгрузитьЗначения()); 					
					ВставитьНовыйУзелВГраф(НовыйГраф,Индекс,НовыеУзлы,ВставляемыеУзлы,"Шаблон",Граф,АтрибутыГрафа);
				ИначеЕсли ДобавитьУзелИзГрафа тогда    
					//3)Добавим узел графа
					НовыеУзлы = новый СписокЗначений;
					НовыеУзлы.ЗагрузитьЗначения(ВставляемыйУзелГраф.ВыгрузитьЗначения()); 					
					ВставитьНовыйУзелВГраф(НовыйГраф,Индекс,НовыеУзлы,ВставляемыеУзлы,"Граф",Шаблон,АтрибутыШаблона);
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		МаксРазмер = макс(Шаблон.Количество(), Граф.Количество());
		Индекс = Индекс + 1;
	КонецЦикла;
КонецПроцедуры

&НаСервере
функция  СгруппироватьОбъединенияВычислитьОшибку(ТабОбъединений,АтрибутыШаблона,АтрибутыГрафа,НовыйГраф,ВставляемыеРёбра,ВставляемыеУзлы)
	СчетчикОшибок = 0;
	КолДобавленныйСвязей = 0;
	Правки = новый Массив;
	
	//в предыдущеё операции получили объединеннные пары узлов. Тут сгруппирую.
	ЗАпрос = новый запрос("ВЫБРАТЬ
	|	таб.ДобавляемыУзел КАК ДобавляемыУзел,
	|	таб.Объединен КАК Объединен,
	|	таб.Источник КАК Источник
	|ПОМЕСТИТЬ Объеденения
	|ИЗ
	|	&таб КАК таб
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	Объеденения.Объединен КАК Объединен,
	|	Объеденения1.ДобавляемыУзел КАК ДобавляемыУзел,
	|	Объеденения1.Источник КАК Источник
	|ИЗ
	|	Объеденения КАК Объеденения
	|		ЛЕВОЕ СОЕДИНЕНИЕ Объеденения КАК Объеденения1
	|		ПО Объеденения.Объединен = Объеденения1.Объединен
	|ИТОГИ ПО
	|	Объединен");
	ЗАпрос.УстановитьПараметр("таб", ТабОбъединений);
	Рез = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	РасмотренныеУзлы= новый Массив;
	
	Пока рез.Следующий() цикл
		//паралельно вычислю ошибку по размеру объединённых ячеек.
		//Известно что либо в графе была разбита ясйека, либо в шаблоне,
		//знаю, какие конкретно, а значит могу сравнить суммы разбитых и исходную
		ДобавленоШаблоном = ложь;
		ДобавленоГрафом = ложь;
		Дет = рез.Выбрать();
		Спис = новый СписокЗначений;
		спис.Добавить(рез.Объединен);
		РасмотренныеУзлы.Добавить(рез.Объединен);
		РазмерШаблон = АтрибутыШаблона[рез.Объединен].РазмерХ*АтрибутыШаблона[рез.Объединен].РазмерУ;
		РазмерГраф = АтрибутыГрафа[рез.Объединен].РазмерХ*АтрибутыГрафа[рез.Объединен].РазмерУ;
		
		пока дет.Следующий() цикл
			спис.Добавить(дет.ДобавляемыУзел);
			ДобавленоШаблоном = макс(ДобавленоШаблоном,дет.Источник = "Шаблон");
			ДобавленоГрафом =макс(ДобавленоГрафом,дет.Источник = "Граф");
			РасмотренныеУзлы.Добавить(дет.ДобавляемыУзел);
			РазмерШаблон = РазмерШаблон + АтрибутыШаблона[дет.ДобавляемыУзел].РазмерХ*АтрибутыШаблона[дет.ДобавляемыУзел].РазмерУ;
			РазмерГраф = РазмерГраф + АтрибутыГрафа[дет.ДобавляемыУзел].РазмерХ*АтрибутыГрафа[дет.ДобавляемыУзел].РазмерУ;
		КонецЦикла;
		если ДобавленоШаблоном и ДобавленоГрафом тогда
			источник = "Непонятно что";
		иначеесли ДобавленоШаблоном тогда
			источник = "Шаблон";
		иначеесли ДобавленоГрафом тогда
			источник = "Граф";
		КонецЕсли;
		Правки.Добавить(новый Структура("Источник,Тип,Узлы",источник,"Объединили",спис));
		Если   источник = "Непонятно что" тогда
			СчетчикОшибок = СчетчикОшибок + спис.Количество();
		ИначеЕсли РазмерШаблон<>РазмерГраф Тогда 
			СчетчикОшибок = СчетчикОшибок + 1;
		КонецЕсли;
	КонецЦикла;
	
	//тут рассмотри все остальные ячейки
	Для инт=0 по НовыйГраф.Количество()-1 цикл
		если РасмотренныеУзлы.Найти(инт)<>Неопределено тогда
			Продолжить;
		КонецЕсли;
		если не АтрибутыГрафа[инт].РазмерХ*АтрибутыГрафа[инт].РазмерУ =  АтрибутыШаблона[инт].РазмерХ*АтрибутыШаблона[инт].РазмерУ тогда
			СчетчикОшибок = СчетчикОшибок + 1;
		КонецЕсли;		
	КонецЦикла;	
	
	//количество новых рёбер с недобавленными узлами
	МасПроверенныйСвязей = новый массив();	
	Для каждого Узел из ВставляемыеРёбра цикл
		Для каждого ребро из Узел.Значение цикл
			поиск = ""+Узел.Ключ+"_"+ ребро.Значение;
			если МасПроверенныйСвязей.Найти(поиск)<>Неопределено тогда
				Продолжить;	
			КонецЕсли;
			поиск = ""+ ребро.Значение+"_"+ Узел.Ключ;
			если МасПроверенныйСвязей.Найти(поиск)<>Неопределено тогда
				Продолжить;	
			КонецЕсли;
			Если ВставляемыеУзлы.найти(ребро.Значение,"Индекс") = Неопределено и  ВставляемыеУзлы.найти(Узел.Ключ,"Индекс") = Неопределено тогда
				КолДобавленныйСвязей = КолДобавленныйСвязей + 1;
				МасПроверенныйСвязей.Добавить(""+Узел.Ключ+"_"+ ребро.Значение);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	//количество новых рёбер с добавленными узлами
	Для каждого стр из ВставляемыеУзлы цикл
		КолДобавленныйСвязей = КолДобавленныйСвязей + НовыйГраф[стр.индекс].Количество();
	КонецЦикла;
	
	возврат новый Структура("СчетчикОшибок,КолДобавленныйСвязей,Правки",СчетчикОшибок,КолДобавленныйСвязей,Правки);
КонецФункции

&НаСервере
функция СравнитьГрафы(Знач Шаблон,Знач Граф,Знач АтрибутыШаблона,Знач АтрибутыГрафа)
	
	//Строим новый граф 
	НовыйГраф = новый Массив;
	
	ВставляемыеУзлы = новый ТаблицаЗначений;
	ВставляемыеУзлы.Колонки.Добавить("Индекс");
	ВставляемыеУзлы.Колонки.Добавить("Источник");
	
	ВставляемыеРёбра = новый Соответствие;
	
	ЗаполнитьНовыйГраф(НовыйГраф,Шаблон,Граф,ВставляемыеУзлы,ВставляемыеРёбра,АтрибутыШаблона,АтрибутыГрафа);
	
	//интерпритируем полученные данные.    	
	ТабОбъединений = новый ТаблицаЗначений;
	ТабОбъединений.Колонки.Добавить("ДобавляемыУзел",новый ОписаниеТипов("Число"));
	ТабОбъединений.Колонки.Добавить("Объединен",новый ОписаниеТипов("Число"));
	ТабОбъединений.Колонки.Добавить("Источник",новый ОписаниеТипов("Строка",,,,новый КвалификаторыСтроки(20)));
	
	ЗаполнитьТаблицуОбъединений(ВставляемыеУзлы,НовыйГраф,ТабОбъединений,ВставляемыеРёбра);
	
	Ответ = СгруппироватьОбъединенияВычислитьОшибку(ТабОбъединений,АтрибутыШаблона,АтрибутыГрафа,НовыйГраф,ВставляемыеРёбра,ВставляемыеУзлы);
	
	КоличествоСвязей = 0;
	Для каждого стр из НовыйГраф цикл
		КоличествоСвязей = КоличествоСвязей + стр.Количество();
	КонецЦикла;
	
	//Все новые рёбра, все новые узлы, все несовпадения по размерам влияют на результат.
	Похожесть = окр(((КоличествоСвязей - Ответ.КолДобавленныйСвязей) + (НовыйГраф.Количество()-Ответ.СчетчикОшибок))/(НовыйГраф.Количество()+КоличествоСвязей)*100);
	
	Для каждого стр из Ответ.Правки цикл
		Сообщить(стр.Источник + " "+стр.узлы);
	КонецЦикла;
	
	возврат Похожесть;
	
КонецФункции

&НаСервере
Процедура ЗаполнитьТаблицуОбъединений(ВставляемыеУзлы,НовыйГраф,ТабОбъединений,ВставляемыеРёбра)
	//Сформируем все рёбра добавленных узлов, без самих добавленных
	СоседниеУзлы = новый СписокЗначений;
	Для каждого Узел из ВставляемыеУзлы цикл		
		Соседние = НовыйГраф[Узел.Индекс];		
		Для каждого СоседнийУзел из Соседние цикл
			Если ВставляемыеУзлы.Найти(СоседнийУзел.Значение,"Индекс")=Неопределено тогда
				если СоседниеУзлы.НайтиПоЗначению(СоседнийУзел.Значение) = Неопределено тогда
					СоседниеУзлы.Добавить(СоседнийУзел.Значение);
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Для каждого Узел из ВставляемыеУзлы цикл				
		Для каждого СосоеднийУзел из СоседниеУзлы цикл
			//Добавленный узел означает, что узел шаблона/графа разбивается на 2. Нужно выяснить какой конкретно узел разбивается.
			//Если исходный узел разбился, то часть рёбер попадёт в добавленные. Нужно проверить если у соседнего узла
			//добавлённые рёбра полностью включают определённую часть рёбер добавленного узла, то эти узлы должны быть объединенны. 
			//Определенная часть  =  все рёбра - добавленные узлы - текущий соседний узел - узлы, иницдентные и добавленному узлу, и соседнему, но ребро не добавлено в соседний узел
			Соседние = НовыйГраф[Узел.Индекс].ВыгрузитьЗначения();
			СоседниеСоседнего = НовыйГраф[СосоеднийУзел.Значение].ВыгрузитьЗначения();
			//удаляю из соседних вставляемые узлы
			Для каждого УдаляемыУзел из ВставляемыеУзлы цикл
				найд = Соседние.найти(УдаляемыУзел.Индекс);
				Если не найд = Неопределено тогда
					Соседние.Удалить(найд);
				КонецЕсли;
			КонецЦикла;
			//найдем массив вставленных    			
			найд = ВставляемыеРёбра.Получить(СосоеднийУзел.Значение);
			если найд = Неопределено тогда МассивВставленныхРёберДляТекущегоУзла = новый Массив иначе МассивВставленныхРёберДляТекущегоУзла = найд.ВыгрузитьЗначения() КонецЕсли;
			
			//теперь из соседних текущего соседнего нужно удалить все рёбра, которые не вставлены, инциндентны и сам узел
			Для каждого УзелСоседниеСоседнего из СоседниеСоседнего цикл
				найд = Соседние.Найти(УзелСоседниеСоседнего);
				Если найд<>Неопределено и МассивВставленныхРёберДляТекущегоУзла.Найти(УзелСоседниеСоседнего) = Неопределено   тогда
					Соседние.Удалить(найд);
				КонецЕсли;
			КонецЦикла;
			найд = Соседние.найти(СосоеднийУзел.Значение);
			Если найд<>Неопределено тогда
				Соседние.Удалить(найд);
			КонецЕсли;
			//если связь всего одна, то проверяем на равенство
			входит = ложь;
			если Соседние.количество()=1 тогда
				входит = Соседние.Количество() = МассивВставленныхРёберДляТекущегоУзла.Количество() и Соседние[0]= МассивВставленныхРёберДляТекущегоУзла[0];
			иначе
				входит = КоэфициентВхожденияСписка1ВСписке2(Соседние,МассивВставленныхРёберДляТекущегоУзла) = 0;
			КонецЕсли;	
			//проверим, что один входит в другой
			если входит тогда		
				//соеденены
				нов = ТабОбъединений.Добавить();
				нов.ДобавляемыУзел = Узел.Индекс;
				нов.Источник = Узел.Источник;
				нов.Объединен = СосоеднийУзел.Значение;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

Основная функция - СравнитьГрафы. В комментариях более-менее описаны нюансы. Пример использования

РезультатШаблон = РазобратьТаблицу_Область(макет,макет.области.Область1);
РезультатМатрица = РазобратьТаблицу_Область(макет,макет.области.Область2);
сообщить(""+СравнитьГрафы(РезультатШаблон.СписокСмежности,РезультатМатрица.СписокСмежности,РезультатШаблон.АтрибутыУзлов,РезультатМатрица.АтрибутыУзлов) +" % похожи");

Это функции из предыдущей статьи.

Теперь на простом примере опишу как работает сам алгоритм. Возьмём две таблицы.

Их графы следующие.

Списки смежностей такие

 

Шаблон Граф Новый 
( {1,4}
 {0,2,5}
 {1,3,6}
 {2,7}
 {0,5,8}
 {1,4,6,9}
 {2,5,7,10}
 {3,6,11}
 {4,9,12}
 {5,8,10,13}
 {6,9,11,14}
 {7,10,15}
 {8,13}
 {9,12,14}
 {10,13,15}
 {11,14})
( {1,4}
 {0,2,5}
 {1,3,5}
 {2,6}
 {0,5,7}
 {1,2,4,6,7,8,10,11}
 {3,5,8}
 {4,5,9}
 {5,6,12}
 {7,10}
 {5,9,11}
 {5,10,12}
 {8,11})
()

 

Строим новый граф. Смотрим 0 узел. И в шаблоне и в графе одинаковы. Пишем в новый граф.

1 узел, аналогично.

2 узел, рёбра отличаются. Рассмотрим следующие узлы {2,7} и {2,6}. Так как ошибка может быть в следующих узлах, это может влиять на нумерацию. Увеличим номер тех узлов, которые больше 2 и сравним. Получаем {2,8} и {2,7}. Теперь сравниваем {2,8} и {2,6}, {2,7} и {2,7}. Рёбра совпадают, значит ничего не делаем, добавляем в новый граф.

3 узел - аналогично. Возникают следующие рёбра {0,6,9} и {0,5,7}, {0,5,8} и {0,6,8}. При сравнении ошибка при ничего не делать - 0.5, при вставке узла из шаблона - 100, при вставке из графа - 100. Ничего не делаем, добавляем в новый граф.

4 узел - аналогично 3, ничего не делаем, добавляем в новый граф.

5 узел. Если ничего не делать, то следующие узлы будут {3,5,8} и {2,5,7,10}. Даже если увеличивать номера, то минимальная ошибка будет 0.5. Если добавить узел из графа, ошибка - 1, если добавить из шаблона узел {1,4}, то следующие узлы должны быть {2,5,7,10} и {2,5,7,8,9,11,12}. Ошибка - 0.33. Поэтому вставляем узел из шаблона в граф, в новый граф.

И так далее. 6, 7, 8, 11, 12, 13, 14, 15  узлы оставляются, 9,10 - добавляются. По итогу получается.

Шаблон Граф Новый 
( {1,4}
 {0,2,5}
 {1,3,6}
 {2,7}
 {0,5,8}
 {1,4,6,9}
 {2,5,7,10}
 {3,6,11}
 {4,9,12}
 {5,8,10,13}
 {6,9,11,14}
 {7,10,15}
 {8,13}
 {9,12,14}
 {10,13,15}
 {11,14})
( {1,4}
 {0,2,6}
 {1,3,6}
 {2,7}
 {0,6,8}
 {}
 {1,2,4,7,8,11,13,14}
 {3,6,11}
 {4,6,12}
 {}
 {}
 {6,7,15}
 {8,13}
 {6,12,14}
 {6,13,15}
 {11,14})
( {1,4}
 {0,2,5,6}
 {1,3,6}
 {2,7}
 {0,5,6,8}
 {1,4,6,9}
 {1,2,4,5,7,8,10,11,13,14}
 {3,6,11}
 {4,6,9,12}
 {5,8,10,13}
 {6,9,11,14}
 {6,7,10,15}
 {8,13}
 {6,9,12,14}
 {6,10,13,15}
 {11,14})

 

На рисунке оранжевым цветом выделены добавленные узлы и рёбра.

Достаточно чётко видно, что в рёбрах всех добавленных узлов есть узлы инцидентные с 6 и более того, данные рёбра отмечены как добавленные. По данному критерию можно сказать какие узлы должны быть объединены. Для i-го узла рассмотрим все соседние, не добавленные узлы. Если из рёбер i-го узла удалить все другие добавленные узлы, удалить текущий рассматриваемый соседний, а также удалить те узлы, которые инцидентны и i и соседнему, но не являются добавленным для соседнего. То в итоге, оставшиеся рёбра должны полностью включаться в добавленным для соседнего.

То есть, к примеру, у узла 5 рёбра {1,4,6,9}, у узла 6 добавленные  {1,4,5,8,11,13,14}. Удалим узел 6, так как его рассматриваем и узел 9, так как он добавленный. {1,4} оставляем, так как они инцидентны, но в списке добавленных. {1,4} полностью включается в {1,4,5,8,11,13,14}. Значит 5 и 6 объединены.

Рассматривается именно так, потому что смысл добавления узла - это дробление ячейки таблицы, а это значит, что добавленный узел перенимает на себя часть рёбер узла, который дробят.

В итоге, программа поймёт что необходимо объединить {5,6,9,10}. Также программа будет понимать, что узлы вставлены из шаблона, а значит в графе они объединены.

Коэффициент похожести рассчитывается так:

(Количество узлов - количество добавленных узлов - ошибки размеров ячеек)  + (количество рёбер узлов - количество добавленных рёбер, не инцедентных добавленным узлам + количество рёбер добавленных узлов))/(Количество узлов +Количество рёбер)*100

В данном случае: ((16 - 3  - 0) + (60 - 6 - 12))/(60+16) = 72

То есть на 72 % похожи.

Теперь на примере 2 графов из предыдущей статьи. Были такие графы:

Построили новый, получили такой.

 

Если провести расчет описанный выше для добавленных узлов здесь, то получится, что для преобразования шаблона в граф, нужно в шаблоне объединить узлы 4,5 и 6,9, что правильно. 2 графа похожи на 83%.

Данный метод не универсален, на мелких графах (менее 6 узлов) может давать ошибки. Так как знания математического аппарата теории графов недостаточно для обоснования, либо опровержения алгоритма, то, дать гарантий на то, что будет 100% работать на больших графах тоже нельзя. Скорее всего, есть какие-нибудь контрпримеры. Пока такого не встречал.

Специальные предложения

Оставьте свое сообщение

См. также

Онлайн-курс "1С:Специалист-консультант по "1С:Зарплата и управление персоналом" 21-24 июля 2020 года Промо

Решение задач на 1С:Специалист Бухгалтерский учет Зарплата Управление персоналом (HRM) v8 v8::СПР ЗУП3.x БУ УУ Бесплатно (free)

Спрос на специалистов по внедрению "1С:Зарплата и управление персоналом 8" с каждым днем растет. Станьте одним из востребованных специалистов - пройдите обучение по актуальной редакции 1C:ЗУП 3.1.

13200 руб.

14.06.2018    11209    4    4    

3 онлайн-курса по 1С-программированию: обмен данными, расчетные задачи и бухгалтерские задачи с 12 мая по 8 июля 2020 г.

Практика программирования v8 Бесплатно (free)

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

22.04.2020    4630    23    Infostart    2    

Универсальные инструменты 1С

Универсальные обработки Прочие инструменты разработчика v8 1cv8.cf Бесплатно (free)

Свободно распространяемый набор универсальных обработок и отчетов в виде расширения для разработки и поддержки, которое работает во ВСЕХ видах клиентских приложений и во всех операционных системах, которые поддерживает платформа 1С:Предприятие, кроме мобильных. Консоль запросов - консоль отчетов - консоль кода - редактор объектов базы данных - удаление помеченных объектов - поиск и удаление дублей - редактор констант - консоль заданий - групповая обработка справочников и документов - динамический список - поиск ссылок на объект - регистрация изменений для обмена данными - структура хранения базы - консоль HTTP запросов-консоль вебсервисов- консоль сравнения данных- информация о лицензиях- загрузка из табличного документа-файловый менеджер-все функции- навигатор по конфигурации-конструктор регулярных выражений-Выгрузка загрузка XML с фильтрами

21.01.2020    21430    295    cprit    94    

[СКД] Программное создание схемы компоновки данных

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Сделаем отчет на СКД полностью программно, без использования макета "схема компоновки данных".

15.01.2020    18524    0    John_d    22    

Подсистема "Инструменты разработчика" v5.42 Промо

Инструментарий разработчика v8 1cv8.cf Бесплатно (free)

Интегрированный набор инструментов разработчика: - консоль кода - консоль запросов - консоль построителя отчетов - консоль компоновки данных - консоль заданий - конструктор запроса - справочник алгоритмов - исследователь объектов - интерфейсная панель - настройка журнала регистрации - анализ журнала регистрации - настройка техножурнала - анализ техножурнала - подбор и обработка объектов - редактор объекта БД - редактор констант - редактор параметров сеанса - редактор изменений по плану обмена - редактор пользователей - редактор предопределенных - редактор хранилищ настроек - динамический список - поиск дублей и замена ссылок - контекстная подсказка - синтакс-помощник - поиск битых ссылок - поиск ссылок на объект - структура хранения БД - удаление объектов с контролем ссылок - и прочее

23.09.2007    482262    4340    tormozit    2678    

Таблица значений. Нюансы

Практика программирования v8 Бесплатно (free)

Обзор некоторых аспектов использования общеизвестного инструмента 1С.

01.10.2019    28219    0    Yashazz    45    

[Шпаргалка] Программное создание элементов формы

Практика программирования Работа с интерфейсом v8 1cv8.cf Бесплатно (free)

Программное создание практически всех популярных элементов формы.

06.09.2019    39753    0    rpgshnik    62    

Агрегатные функции СКД, о которых мало кто знает

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Пользуетесь ли Вы всеми возможными агрегатными функциями, которые предоставляет система компоновки данных? Если Вы используете только: СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ, СРЕДНЕЕ, то эта статья для Вас.

05.09.2019    41887    0    ids79    54    

Как я начал администрировать сервер 1С: Предприятие 8.3 с телефона Промо

Администрирование данных 1С Мобильная разработка v8 Бесплатно (free)

Развитие инструментов управления кластером серверов 1С:Предприятие 8.3.

14.04.2017    59095    0    user700211_a.straltsou    27    

Обмен данными. Консистентность vs Многопоточность

Интеграция v8 1cv8.cf Бесплатно (free)

Рассмотрим теоретические основы обмена данными. Какие бывают обмены, какие гарантии при этом даются, зачем идти на компромиссы и что при этом может пойти не так. Есть ли идеальная схема?

03.09.2019    11342    0    m-rv    1    

Функции СКД: ВычислитьВыражение, ВычислитьВыражениеСГруппировкойМассив

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Подробное описание и использование внутренних функций системы компоновки данных: Вычислить, ВычислитьВыражение, ВычислитьВыражениеСГруппировкойМассив, ВычислитьВыражениеСГруппировкойТаблицаЗначений.

08.08.2019    65305    0    ids79    40    

Обработчики событий при записи объектов. Зачем и что за чем?

Математика и алгоритмы v8 Бесплатно (free)

Программисту, имеющему немного опыта на платформе 1С 8.3, бывает сложно разобраться: ПередЗаписью, ПриЗаписи, ПослеЗаписи, на сервере, на клиенте, в модуле формы, в модуле объекта.... Эта шпаргалка была создана в процессе обучения и реального опыта с целью разложить всё по полочкам, чтобы было четкое понимание в каком случае какой обработчик нужно использовать и в какой последовательности они запускаются при записи и проведении документов. Данная статья будет полезна в большей степени начинающим разработчикам. Но и опытным позволит освежить информацию, упорядочить её.

25.07.2019    40341    4    AlbinaAAA    27    

Копирование числовых ячеек из 1С в Excel Промо

Загрузка и выгрузка в Excel Администрирование данных 1С v8 1cv8.cf Бесплатно (free)

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

15.01.2019    21646    0    itriot11    23    

Создание отчетов с помощью СКД - основные понятия и элементы

Практика программирования Математика и алгоритмы v8 v8::СКД Бесплатно (free)

Основные принципы работы СКД. Понятия схемы компоновки и макета компоновки. Описание основных элементов схемы компоновки: наборы данных, поля, вычисляемые поля, ресурсы, параметры.

25.06.2019    46001    0    ids79    25    

Подсистема "Варианты отчетов". Используете ли Вы ее правильно?

Работа с интерфейсом БСП (Библиотека стандартных подсистем) v8 1cv8.cf Бесплатно (free)

Небольшая история про использование подсистемы "Варианты отчетов" из БСП. Используете ли Вы ее правильно?

04.06.2019    37291    0    YPermitin    52    

Выгрузка документа по условию

Практика программирования Разработка v8 Бесплатно (free)

Что делать, если документы нужно выгружать не все подряд, а по какому-то фильтру: статусу, дате, набору условий... А что если он соответствовал этим условиям, а потом перестал? А если потом опять начал? Такие ситуации заставили попотеть не одного программиста.

25.04.2019    15409    0    m-rv    2    

Использование программных перечислений, ч.1: строковые константы Промо

Практика программирования v8 1cv8.cf Бесплатно (free)

Часто ли у вас возникает необходимость в коде выполнять сравнение на строку?

10.12.2016    35505    0    unichkin    45    

Как настроить правильную техподдержку (helpdesk, service desk на коленке)

Управление услугами и сервисом Управление взаимоотношениями с клиентами (СRM) Документооборот и делопроизводство Монитор заказов Учет рабочего времени Управление взаимоотношениями с клиентами (СRM) Документооборот и делопроизводство Монитор заказов Учет рабочего времени v8 УУ Бесплатно (free)

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

24.04.2019    16107    0    siddy    0    

Преобразование EXCEL в таблицу значений без COM и других извращений

Загрузка и выгрузка в Excel v8 1cv8.cf Бесплатно (free)

Получение таблицы значений из excel в 1С v8, без COM, внешних источников данных и т.д. EXCELВТаблицуЗначений() - За 10 строчек кода! Реализация протестирована на 1С 8.3.12.1714 (x64).

18.04.2019    25811    9    Eret1k    43    

Как прикрутить ГУИД к регистру сведений

Практика программирования Перенос данных из 1C8 в 1C8 Разработка v8 Бесплатно (free)

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

16.04.2019    19176    0    m-rv    17    

Вспомогательные инструкции в коде 1С Промо

Практика программирования v8 1cv8.cf Бесплатно (free)

Помогаем редактору кода 1С помогать нам писать и анализировать код.

15.10.2018    27940    0    tormozit    100    

Excel vs 1С: битва с неожиданным исходом

Анализ учета Универсальные обработки Загрузка и выгрузка в Excel Финансовые Управленческие v8 1cv8.cf Россия Бесплатно (free)

Что лучше 1С или Excel? Разберемся, в казалось бы, очевидном, чтобы получить невероятное!

11.04.2019    34899    0    bolefirenko    116    

Универсальные функции ЗУП 3.1 / ЗКГУ 3.1, которые помогут в разработке

Универсальные функции Зарплата Управление персоналом (HRM) Зарплата v8 v8::СПР ЗКГУ3.0 ЗУП3.x БУ Бесплатно (free)

В статье размещен список стандартных процедур и функций с примерами, которые могут помочь при разработке (доработке) конфигураций Зарплата и управление персоналом ред. 3.1 и Зарплата и кадры государственного учреждения 3.1. Иногда бывает довольно сложно правильно получить данные или долго, поэтому лучшим вариантом будет использование стандартных процедур. Буду очень признателен, если Вы поделитесь своим опытом и предложите свои варианты стандартных процедур которые помогают в работе. Или предложите, как дополнить имеющиеся процедуры.

14.11.2018    74839    0    GeterX    112    

Оформление и рефакторинг сложных логических выражений Промо

Практика программирования v8 Россия Бесплатно (free)

В сложных логических выражениях нередко самому автору спустя какое-то время тяжело разобраться, не говоря уже о других программистах. Предлагаемая методика позволяет повысить наглядность таких выражений путем оформления в виде И-ИЛИ дерева и одновременно выполнять их рефакторинг.

20.09.2012    75423    0    tormozit    129    

Автоматические и управляемые блокировки применительно к типовым конфигурациям 1С

Математика и алгоритмы Практика программирования v8 v8::blocking 1cv8.cf Бесплатно (free)

Основные принципы работы с режимами автоматических и управляемых блокировок в 1С Предприятие 8. Теория и применение в типовых конфигурациях: БП, УТ, ЕРП

10.11.2018    32421    0    ids79    40    

Git + 1С. Часть 1. Как подключиться к команде разработки и начать использовать Git

Инструментарий разработчика Управление проектом v8 1cv8.cf Бесплатно (free)

Первая статья из цикла инструкций по работе с Git в 1С-разработке. Рассмотрим, как настроить рабочее место, как получить свою "копию" проекта для разработки и приступить к полезным действиям. Все примеры будут изложены в рамках трёх практических кейсов: 1. Моя команда дорабатывает типовую конфигурацию, использует приватный репозиторий на BitBucket, в котором версионируются внешние отчеты/обработки, расширения конфигураций и правила обмена; 2. Я участвую в стартап-команде, которая разрабатывает свою конфигурацию с использованием Git и GitLab; 3. Я принимаю участие в развитии OpenSource-продукта на GitHub как заинтересованный разработчик (контрибьютор).

18.10.2018    61161    0    stas_ganiev    73    

Из Excel в 1С запросом

Загрузка и выгрузка в Excel v8 1cv8.cf Бесплатно (free)

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

14.08.2018    19315    0    m-rv    5    

Запись значения в поле ввода/формы со срабатыванием события ПриИзменении Промо

Практика программирования v8 1cv8.cf Россия Бесплатно (free)

Иногда возникает необходимость после записи значения в какое либо поле ввода/формы вызвать для него обработчик события ПриИзменении, а о вызове самого события приходится только мечтать. В этой статье приводится программный способ вызова этого события.

11.07.2007    46321    0    tormozit    38    

Тестер: частые вопросы

Практика программирования v8 Бесплатно (free)

Ошибкам бой - тесты норма жизни!

25.07.2018    27534    0    grumagargler    26    

Повышаем эффективность разработки правил обмена

Практика программирования Перенос данных из 1C8 в 1C8 v8 КД Бесплатно (free)

Как повысить скорость и качество разработки правил обмена? Как вести групповую разработку правил обмена? Как облегчить сопровождение правил обмена после передачи в эксплуатацию? Об этом и многом другом вы можете узнать из этой статьи.

25.06.2018    27299    0    olegtymko    47    

Как сделать запрос на изменение данных

Практика программирования v8 v8::Запросы 1cv8.cf Бесплатно (free)

В статье приведены особенности внутренней архитектуры и примеры работы с расширением языка запросов 1С.

01.06.2018    28826    0    m-rv    21    

Как сделать из &НаКлиентеНаСервереБезКонтекста почти &НаКлиентеНаСервере Промо

Практика программирования v8 1cv8.cf Россия Бесплатно (free)

Как сделать метод формы, доступный на клиенте и на сервере одновременно, и сохранить при этом удобство разработки

10.09.2017    42346    0    tormozit    74    

Строим графы средствами 1С (без GraphViz)

Практика программирования v8 Бесплатно (free)

Множество статей на Инфостарте описывают, как работать с компонентой GraphViz, чтобы построить ориентированный граф. Но практически нет материалов, как работать с такими графами средствами 1С. Сегодня я расскажу, как красиво строить графы с минимальным пересечением. Нам этот метод пригодился для отрисовки алгоритмов в БИТ.Финансе, т.к. типовой механизм не устраивал. Еще это может быть полезно для визуализации различных зависимостей: расчета себестоимости, графы аффилированности компаний и т.д. Надеюсь, эта статья поможет сделать мир 1С красивее и гармоничней:) Итак, поехали...

23.05.2018    23500    0    slozhenikin_com    20    

Распределение расходов пропорционально продажам

Финансовый учет и бюджетирование (FRP) Учет доходов и расходов Практика программирования Финансовый учет и бюджетирование (FRP) Учет доходов и расходов v8 v8::ОУ УТ10 УУ Бесплатно (free)

Финансовая модель. Распределение административных расходов по подразделениям пропорционально продажам за месяц. Дополнительные реквизиты против бизнес-процессов!

13.05.2018    17658    0    Rustig    9    

Универсальный обмен между идентичными конфигурациями через REST интерфейс OData. Часть І: Справочники

Перенос данных из 1C8 в 1C8 v8 Бесплатно (free)

Сейчас все чаще интеграции различных конфигураций проектируются через HTTP-сервисы - они и работают быстрее, и "войти" в режим отладки гораздо проще, тем самым обойдя "черный ящик" универсального обмена через xml, например. Более года назад я начал работать в компании, в которой разработчики работали с конфигурациями 1С в режиме совместимости еще 8.2.16 (менять режим совместимости в типичных базах мы не хотели) - а как Вы наверное знаете, если интересовались HTTP-сервисами в 1С, их использование в режиме совместимости 8.3.4 и ниже недопустимо - и здесь я уже не надеялся на разработку и использование HTTP-сервисов. Но позже меня заинтересовал такой "сервис" как REST интерфейс OData, так как его можно использовать не меняя режим совместимости конфигурации - именно он и стал для меня идеальным вариантом решения "нетривиальных" задач.

11.05.2018    22175    0    V.Stavinsky    11    

Минимализмы 3

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

Очередная серия "минимализмов" [http://infostart.ru/public/306536/, https://infostart.ru/public/460935/]. Также, как и в предыдущих статьях, здесь приведена подборка коротких оригинальных авторских решений некоторых задач. Ранее эти решения были разбросаны по моим комментариям к чужим публикациям.

19.02.2018    44918    0    ildarovich    45    

Этюды по программированию. Взаимодействие с Microsoft Word

Практика программирования v8 Бесплатно (free)

Часто приходится заниматься созданием сложных документов Word с таблицами, вложенными фрагментами, хитрым оформлением и прочими радостями жизни. Это - попытка как-то структурировать полученный опыт, чтобы не приходилось перерывать ворох старых обработок в поисках крупиц истины. Надеюсь, эта статья будет полезна и Вам.

11.12.2017    31662    0    milkers    23    

Метод формирования движений в типовых регистрах нетиповыми регистраторами

Практика программирования v8 1cv8.cf Бесплатно (free)

Вариант решения задач с проведением по типовым регистрам нетиповыми регистраторами. Зачем - чтобы при сравнении конфигурации не обращать внимание на свойства регистров и исключить вероятность допущения горькой оплошности при обновлении информационных баз, заменив типы регистраторов основной конфигурации типами конфигурации поставщика. Для программных продуктов, имеющих в своем составе метаданных документ "Корректировка регистров"("Корректировка записей регистров").

05.12.2017    26864    0    itriot11    34    

1С: Конвертация данных 3. Инструкции и примеры. EnterpriseData (универсальный формат обмена)

Перенос данных из 1C8 в 1C8 Практика программирования Обмен через XML v8 КД Бесплатно (free)

Что такое КД3? Как начать использовать? Полезные дополнения к документации. Что нужно исправить в типовых обработках и конфигурации. Как изменить правила обмена не снимая конфигурацию с поддержки. Как отлаживать правила обмена?

19.11.2017    182428    0    MaxS    285    

Обзор имеющихся библиотек OneScript

OneScript v8 Бесплатно (free)

Экосистема OneScript активно развивается. Количество пользователей данного интерпретатора и имеющихся библиотек неуклонно растет, количество решаемых проблем - тоже. Однако остро встает вопрос некоторой разобщенности и размазанности информации по имеющимся библиотекам, их функциональности и проблемам, которые они решают. Данная статья призвана навести порядок в этой теме.

14.11.2017    42246    0    nixel    86    

Программные перечисления, ч.2: приемы кэширования при разработке

Практика программирования v8 Бесплатно (free)

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

30.10.2017    26160    0    unichkin    18    

Легкий способ обновления измененной конфигурации

Инструментарий разработчика v8 Бесплатно (free)

Легкий способ обновления измененной конфигурации. Сервис подготовки расширения конфигурации

25.10.2017    22734    0    avk72    63    

Работа с Excel

Практика программирования Загрузка и выгрузка в Excel v8 Бесплатно (free)

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

23.10.2017    40950    0    arakelyan    39    

Ускоряем 1С: модули с повторным использованием возвращаемых значений

Практика программирования v8 Бесплатно (free)

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

04.09.2017    51015    0    m-rv    61