Ввод по строке (переопределение)

10.09.15

Разработка - Механизмы платформы 1С

Предлагаю простое решение, которое позволяет сделать ввод по строке более удобным для пользователя.

При работе с клиентом столкнулся с пожеланием к вводу по строке при заполнении документа "Реализация товаров и услуг".

А именно было необходимо, чтобы система искала нужную номенклатуру, при наборе с клавиатуры не только по первым символам (это стандартное поведение), но и по вхождению введенных символов в название.  

 

Рассмотрим пример. Допустим, есть список номенклатуры, в котором есть - газета "Ярмарка":

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

Решить данную задачу нам поможет обработчик модуля менеджера - ОбработкаПолученияДанныхВыбора().

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

Итак, обращаемся к модулю менеджера справочника "Номенклатура":

 Контекс выполнения этой процедуры - это "сервер", поэтому в получении нужного нам списка мы сможем использовать запрос. В реализации нашей задачи нам поможет оператор запроса "ПОДОБНО" и определенная маска для наименования:

Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Номенклатура.Ссылка
		|ИЗ
		|	Справочник.Номенклатура КАК Номенклатура
		|ГДЕ
		|	Номенклатура.Наименование ПОДОБНО &Наименование";
		
		
	Запрос.УстановитьПараметр("Наименование", "%" + Параметры.СтрокаПоиска + "%");
	
	РезультатЗапроса = Запрос.Выполнить();
	Таблица = РезультатЗапроса.Выгрузить();
	Массив = Таблица.ВыгрузитьКолонку("Ссылка");
	
	ДанныеВыбора = Новый СписокЗначений;
	ДанныеВыбора.ЗагрузитьЗначения(Массив);
	СтандартнаяОбработка = Ложь;

	
КонецПроцедуры
 

 Отметим, что в нашем обработчике - ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбраблтка) для нас важны все три параметра. В первый "ДанныеВыбора" мы загружаем наш список номенклатуры, полученный по нашему алгоритму. Из параметра "Параметры" мы получим значение введенное пользователем, а третьему параметру "СтандартнаяОбработка" мы должны поставить значение "Ложь"(отключаем стандартный алгоритм системы).

В результате одной небольшой процедурой мы полностью решили поставленную задачу:

 Данный способ решиния задачи я использовал еще на Платформе 2.0. Как подсказали в комментариях коллеги в Платформе 3.0 задача решается ещё проще. В справочнике на закладке "Поле ввода" можно выбрать режим ввода по строке. Там два варианта: "начало" и "любая часть". 

      Однако описанный в статье способ использования обработчика модуля менеджера - ОбработкаПолученияДанныхВыбора() хорошо подойдет, если понадобится другой вариант работы алгоритма ввода по строке, ну или если у Вас все ещё платформа 8.2.

Ввод по строке.

См. также

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    4583    dsdred    53    

73

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

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

24.01.2024    5303    YA_418728146    25    

63

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6429    dsdred    36    

112

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    18494    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12102    human_new    27    

74

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8845    YA_418728146    6    

141

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6284    sebekerga    54    

94

Все скопируем и вставим! (Буфер обмена в 1С 8.3.24)

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    16003    SeiOkami    31    

103
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. blindcat2006 88 10.09.15 07:41 Сейчас в теме
Прикольно, наверное, но... (см картинку)
Хотя если для других вариантов использовать - для новичков пойдет
Прикрепленные файлы:
SagittariusA; Monex; Aleskey_K; Hexed; PLAstic; Gang031; Magnastrag; Aleksey.Bochkov; NeviD; dj_serega; BigB; FullMoon; niko11s; anig99; ojiojiowka; superkuzja; mmoozzgg; +17 Ответить
2. anig99 2843 10.09.15 09:06 Сейчас в теме
(1) blindcat2006, Чутка подправить статью и будет годна. То, что на картинке, появилось только в 8.3, а ОбработкаПолученияДанныхВыбора есть уже в 8.2 на управляемых формах.
15. PLAstic 295 15.10.19 14:16 Сейчас в теме
(2) Более того, чтобы не колхозить, можно применить свои условия к тому списку, что выдаст сама платформа. Метод ПолучитьДанныеВыбора().
9. pentanom 25 16.09.15 11:42 Сейчас в теме
(1) blindcat2006, А у меня почему-то это не работает :(
Конфигурация 11.1.10.180
Платформа 8.3.6.2152
3. klinval 337 10.09.15 12:49 Сейчас в теме
Данный способ решиния задачи я использовал еще на Платформе 2.0. Как подсказали в комментариях коллеги в Платформе 3.0 задача решается ещё проще.

Платформа 2.0 и 3.0? Может платформа 8.2 и 8.3 или конфигурация Бухгалтерия предприятия 2.0 и 3.0? Когда работал во франче у нас менеджеры так путались, не думал, что программист может также запутаться...
Сама публикация нормальная, правда я уже давно на платформе 8.3 сижу, поэтому вряд ли мне понадобится данные в публикации наработки.
cleaner_it; BigB; pt_olga; +3 Ответить
4. niko11s 989 10.09.15 13:06 Сейчас в теме
5. Brawler 454 10.09.15 13:12 Сейчас в теме
стоило бы ограничить число строк возвращаемых запросом
6. dtripleh 10.09.15 14:24 Сейчас в теме
Зачем это всё, когда в платформе реализован ввод по строке по любой части?

p.s Понял. Недочитал:)
7. monkbest 115 11.09.15 10:12 Сейчас в теме
Есть минусы:
1. Производительность. номенклатура - справочник содержащий тысячи позиций даже в небольшой фирме. Выражение ПОДОБНО - медленное по сравнению с вырезанием первых n символов. Я бы сначала проанализировал длину строки поиска и допустим искал бы от 3ех или 4ех символов, если введен 1 символ или два отказ = истина. Еще бы добавил в запрос Выбрать первые 5-6, т.к. больше в список выбора один фиг не поместится
2. Вы убили поиск по коду и артикулу. В ЗУП 3.0 в свое время убили ввод сотрудника по табельному т.к. косячно запрос написали. Т.е. они учли поиск по табельному, но сравнивали табельный с кодом физ.лица а не сотрудника :) у Вас это вообще не учтено. Т.е. надо писать столько условий ПОДОБНО через ИЛИ, сколько у Вас полей используется для ввода по строке. Универсально будет пройтись по метаданным справочника и кодом сгенерить текст условия по всем полям. Это позволит в дальнейшем, если кто добавит еще один реквизит для ввода по строке, он не будет ломать мозг почему не работает, пока не найдет Вашу процедуру.

a_l_e_xj; kivals; TreeDogNight; jobkostya1c_ERP; Рамзес; IgorS; ivanov660; BigB; +8 Ответить
8. mickey.1cx 397 11.09.15 14:59 Сейчас в теме
Где то месяц назад мне потребовался ввод по строке с поиском по реквизитам справочника, включая неограниченные строковые.
Реализовал через полнотекстовый поиск, из плюсов - произвольный порядок слов
при вводе по строке.
Leon75; Isonic; hafgwkvs; +3 Ответить
10. V.Nikonov 120 16.09.15 12:22 Сейчас в теме
Данный принцип позволит искать элементы по специфичным данным, не являющихся реквизитами элементов! Например, искать Контрагента по номеру телефона (регистр, Контактные данные) и тому подобное... Вводимая подстрока может быть свойством, родителем или тем чем требуется. Подстрока поиска может быть подвержена транслитерации, замене раскладки и т.д.
Автору +
zolotieluga; йцукенг; +2 Ответить
11. vdmkvrshn 14 11.03.17 17:53 Сейчас в теме
Хорошее решение, пользователям такой поиск нравится. Только вот ничего новаторского в нем нет, т.к. это сделано в типовой УТ11, например,в справочниках Партнеров, Номенклатуры и может еще где-то. Я его переделал, расширив поиском по данным контактной информации партнеров, контрагентов, контактных лиц партнеров. А также сделал выделение найденного фрагмента строки цветом, как это работает при стандартном поиске платформой. Вот могу показать фрагментно основные куски кода:


// Функция возвращает список значений ДанныеВыбора. См. СП "ОбработкаПолученияДанныхВыбора"
//
// Параметры:
//  Параметры			 - Структура - Параметры выбора из события ОбработкаПолученияДанныхВыбора
//  СтандартнаяОбработка - Булево - Выходной параметр. Признак выполнения стандартной обработки при вызове из события ОбработкаПолученияДанныхВыбора
//
Функция НайтиЭлементыСправочника(Параметры, СтандартнаяОбработка = Истина) Экспорт
	
// .......................
		Если НЕ ЗначениеЗаполнено(СтрЗаменить(Параметры.СтрокаПоиска, "@", "")) Тогда
			Возврат ДанныеВыбора; // здесь пустой список
		КонецЕсли;	

		Запрос.Текст = ПолучитьТекстЗапросаПоиска(Параметры.СтрокаПоиска, СтрокаОтбора);
		Параметры.СтрокаПоиска = СтрЗаменить(СокрЛП(Параметры.СтрокаПоиска), " ", "%");
		Если Лев(Параметры.СтрокаПоиска, 1) = "@" Тогда
			Параметры.СтрокаПоиска = Прав(Параметры.СтрокаПоиска, СтрДлина(Параметры.СтрокаПоиска) - 1);
		КонецЕсли;
		
		Запрос.УстановитьПараметр("СтрокаВвода",Параметры.СтрокаПоиска + "%" );

		Выборка = Запрос.Выполнить().Выбрать();
		
		СформироватьСписокВыбораДляПоляВводаСправочника(ДанныеВыбора, Выборка, Параметры);
КонецПроцедуры

Функция ПолучитьТекстЗапросаПоиска(ПоисковаяСтрока, СтрокаОтбора)
	
	ПоискПоАдресамЭП = Лев(ПоисковаяСтрока, 1) = "@";
	ПоискНомерам = Найти("0123456789", Лев(ПоисковаяСтрока, 1)) > 0;
	
	ТекстЗапроса = 
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ ПЕРВЫЕ 0
	|	ЗНАЧЕНИЕ(Справочник.Партнеры.ПустаяСсылка) КАК Ссылка,
	|	"""" КАК Представление,
	|	ЛОЖЬ КАК ПометкаУдаления,
	|	"""" КАК ЗначениеПоля,
	|	"""" КАК НайденоПо
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|";
	
	Если ПоискПоАдресамЭП Тогда
		ТекстЗапроса = ТекстЗапроса + 
		"ВЫБРАТЬ ПЕРВЫЕ 20
		|	Партнеры.Ссылка,
		|	ПРЕДСТАВЛЕНИЕ(Партнеры.Ссылка),
		|	Партнеры.ПометкаУдаления,
		|	ПартнерыКонтактнаяИнформация.Представление,
		|	""НайденоПоКИ""
		|ИЗ
		|	Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Партнеры КАК Партнеры
		|		ПО ПартнерыКонтактнаяИнформация.Ссылка = Партнеры.Ссылка
		|			И (ПартнерыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты))
		|ГДЕ
		|	ПартнерыКонтактнаяИнформация.Представление ПОДОБНО &СтрокаВвода
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|ВЫБРАТЬ ПЕРВЫЕ 20
		|	Партнеры.Ссылка,
		|	ПРЕДСТАВЛЕНИЕ(Партнеры.Ссылка),
		|	Партнеры.ПометкаУдаления,
		|	КонтрагентыКонтактнаяИнформация.Представление,
		|	""НайденоПоКИ""
		|ИЗ
		|	Справочник.Контрагенты.КонтактнаяИнформация КАК КонтрагентыКонтактнаяИнформация
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Партнеры КАК Партнеры
		|		ПО КонтрагентыКонтактнаяИнформация.Ссылка.Партнер = Партнеры.Ссылка
		|			И (КонтрагентыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты))
		|ГДЕ
		|	КонтрагентыКонтактнаяИнформация.Представление ПОДОБНО &СтрокаВвода
                // ...............................
                ";
КонецФункции

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


Показать
12. slitov 7 29.09.17 15:47 Сейчас в теме
13. MaiorovYury 10 16.05.18 12:17 Сейчас в теме
Спасибо!
Сделал ограничение для определенных пользователей (что-то вроде RLS) с помощью этой штуки
14. group2tts 04.09.18 15:47 Сейчас в теме
Выкладываю свою написанную функцию для подсвечивания при поиске без учета регистра.

Функцию ВернутьФорматированнуюСтрокуПоиска необходимо добавить в СтроковыеФункцииКлиентСервер

Пример использования ниже:

Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
	ДанныеВыбора = Новый СписокЗначений;
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 10
	|	Номенклатура.Ссылка,
	|   Номенклатура.Код
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|ГДЕ
	|	(Номенклатура.Наименование ПОДОБНО &Наименование ИЛИ Номенклатура.Код ПОДОБНО &Код )
	|	И НЕ Номенклатура.ПометкаУдаления
	|	И НЕ Номенклатура.Родитель.Наименование = ""Удалённые""
	| 	И НЕ Номенклатура.ЭтоГруппа";
	
	Запрос.УстановитьПараметр("Наименование", "%" + Параметры.СтрокаПоиска + "%");
	Запрос.УстановитьПараметр("Код", "%" + Параметры.СтрокаПоиска + "%");
	
	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
	     Структура = Новый Структура("Значение", ВыборкаДетальныеЗаписи.Ссылка);
		 Элемент = ДанныеВыбора.Добавить();
		 Элемент.Значение = Структура;
		 Элемент.Представление = ВыборкаДетальныеЗаписи[0].Наименование + " (" + ВыборкаДетальныеЗаписи[0].Код + ")";
		 Элемент.Представление = СтроковыеФункцииКлиентСервер.ВернутьФорматированнуюСтрокуПоиска(Элемент.Представление,Параметры.СтрокаПоиска);
	КонецЦикла;
	СтандартнаяОбработка = Ложь;

КонецПроцедуры


Функция ВернутьФорматированнуюСтрокуПоиска(СтрокаДляРазбора, СтрокаПоиска) Экспорт
	СтрокаВВерхнемРегистре = Врег(СтрокаДляРазбора);
	СтрокаПоискаВВерхнемРегистре = Врег(СтрокаПоиска);
	
	ФормСтрока = Новый Массив;
	Для Стр = 1 По СтрЧислоВхождений(СтрокаВВерхнемРегистре, СтрокаПоискаВВерхнемРегистре) Цикл
		Индекс = Найти(СтрокаВВерхнемРегистре, СтрокаПоискаВВерхнемРегистре);
		Если НЕ Индекс = 1 Тогда 
			ФормСтрока.Добавить(Новый ФорматированнаяСтрока(Сред(СтрокаДляРазбора,1,Индекс-1)));
		КонецЕсли;
		ФормСтрока.Добавить(Новый ФорматированнаяСтрока(Сред(СтрокаДляРазбора, Индекс, СтрДлина(СтрокаПоиска)), Новый Шрифт(,,Истина),WebЦвета.ЗеленыйЛес));
		СтрокаДляРазбора = Прав(СтрокаДляРазбора, СтрДлина(СтрокаДляРазбора) - (Индекс + (СтрДлина(СтрокаПоиска)-1)));
		СтрокаВВерхнемРегистре = Прав(СтрокаВВерхнемРегистре, СтрДлина(СтрокаВВерхнемРегистре) - (Индекс + (СтрДлина(СтрокаПоиска)-1)));
	КонецЦикла;
	  ФормСтрока.Добавить(Новый ФорматированнаяСтрока(СтрокаДляРазбора));

	Возврат Новый ФорматированнаяСтрока(ФормСтрока);
КонецФункции
Показать
user621724_Dimav1979; alexex; koks17v; kivals; +4 Ответить
16. Gazulo 25 27.01.21 12:35 Сейчас в теме
Вызывается во время начала ожидания ввода текста
АвтоПодборТекста, AutoCompleteText
В процедуре можно вставить необходимы параметр для передачи например из документа в процедуру ОбработкаПолученияДанныхВыбора(

ПараметрыПолученияДанных.Отбор.Вставить("НашПараметр",НашПараметр);
17. dante 02.02.22 14:36 Сейчас в теме
Спасибо,очень пригодилось,на БП 3.0.103.21 работает отлично, подсветки жаль нет найденного символа, но это мелочи уже.
Оставьте свое сообщение