Нередко разработчики и пользователи сталкиваются с парадоксальной ситуацией: при копировании строки из Microsoft Excel в код или поле поиска 1С элемент справочника не находится. Однако стоит набрать то же самое наименование вручную на клавиатуре, как метод НайтиПоНаименованию мгновенно возвращает нужную ссылку. При визуальном сравнении обе строки выглядят абсолютно одинаково, но оператор сравнения выдает результат Ложь.
Разберем детально, почему так происходит, какие скрытые символы подменяет Excel и какими инструментами платформы 1С очистить входящие данные для гарантированного поиска.
Проанализируем типовую ситуацию. Предположим, мы выполняем поиск следующего вида:
СсылкаИзExcel = Справочники.ТипыПитания.НайтиПоНаименованию("все включено");
СсылкаРучная = Справочники.ТипыПитания.НайтиПоНаименованию("все включено");
Результат = (СсылкаИзExcel = СсылкаРучная); // Возвращает Ложь!
Если разбить строку на отдельные слова и выполнить поиск по каждому из них, то слова по отдельности находятся без проблем. Проблема заключается в разделяющем знаке — обычном на вид пробеле.
Выясним основные причины расхождения визуально одинаковых строк:
Символы.НПП. Веб-страницы, отчеты и таблицы Excel часто форматируют текст с использованием символа неразрывного пробела (Unicode U+00A0), чтобы предотвратить нежелательный перенос слов на новую строку. Для человеческого глаза это стандартный пробел (код 32), но для компьютера и базы данных 1С это совершенно разные символы с разными числовыми кодами.Символы.ВК (код 13) и Символы.ПС (код 10).Символы.Таб (код 9), который также может отображаться как пробельный отступ.Чтобы точно определить, какой именно символ мешает поиску, разберем по шагам посимвольный анализ подозрительной строки. Для этого используем метод встроенного языка КодСимвола.
Посмотрим на пример диагностического фрагмента кода:
СтрокаДляПроверки = "все включено"; // Вставляем скопированное значение
Для Позиция = 1 По СтрДлина(СтрокаДляПроверки) Цикл
ТекущийСимвол = Сред(СтрокаДляПроверки, Позиция, 1);
Код = КодСимвола(ТекущийСимвол);
Сообщить(СтрШаблон("Позиция %1: символ '%2', код: %3", Позиция, ТекущийСимвол, Код));
КонецЦикла;
Если на месте пробела мы увидим код 160 вместо ожидаемого 32, значит, в строке присутствует Символы.НПП. Если в конце строки обнаружатся коды 10 или 13 — это невидимый перевод строки из Excel.
Для базовой нормализации текста, полученного из Excel или внешних файлов обмена, достаточно применить функции СокрЛП и СтрЗаменить. Заменим неразрывный пробел на обычный пробел и удалим случайные краевые отступы:
ИсходныйТекст = "все включено"; // Значение из Excel
// Заменяем неразрывный пробел обычным пробелом
НормализованныйТекст = СтрЗаменить(ИсходныйТекст, Символы.НПП, " ");
// Удаляем концевые переводы строк и пробелы по краям
НормализованныйТекст = СокрЛП(НормализованныйТекст);
// Выполняем точный поиск
НайденнаяСсылка = Справочники.ТипыПитания.НайтиПоНаименованию(НормализованныйТекст, Истина);
Если данные регулярно загружаются из неконтролируемых внешних источников, одной замены Символы.НПП может быть недостаточно. Напишем универсальную функцию очистки строки от всех распространенных артефактов буфера обмена:
Функция ОчиститьСтрокуДляПоиска(Знач ВходнаяСтрока)
// Заменяем различные пробельные разделители на обычный пробел
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символы.НПП, " ");
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символы.Таб, " ");
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символы.ВК, "");
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символы.ПС, "");
// Удаляем невидимые Unicode-маркеры (BOM и пробел нулевой ширины)
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символ(65279), "");
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символ(8203), "");
// Удаляем двойные пробелы, если они образовались после замен
Пока СтрНайти(ВходнаяСтрока, " ") > 0 Цикл
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, " ", " ");
КонецЦикла;
Возврат СокрЛП(ВходнаяСтрока);
КонецФункции
Начиная с версии платформы 8.3.23, в 1С появилась встроенная поддержка регулярных выражений. Это позволяет заменить любые комбинации пробельных символов (включая табуляции, переносы строк и неразрывные пробелы) всего одной строкой кода:
// Регулярное выражение \s+ находит любую непрерывную группу пробельных символов
СтрокаОчищенная = СокрЛП(СтрЗаменитьПоРегулярномуВыражению(СтрокаИзExcel, "\s+", " "));
НайденныйЭлемент = Справочники.ТипыПитания.НайтиПоНаименованию(СтрокаОчищенная, Истина);
Обратим внимание на синтаксис самого метода: НайтиПоНаименованию(<Наименование>, <ТочноеСоответствие>). Второй параметр по умолчанию равен Ложь. Это означает, что платформа выполняет поиск по совпадению первых символов (префиксу).
Ложь сразу потерпит неудачу.ТочноеСоответствие = Истина, 1С требует совпадения абсолютно всей длины строки, включая конечные пробелы.Наименование в конфигураторе. Если в Excel наименование содержит 120 символов, а в справочнике длина поля ограничена 100 символами, точный поиск никогда не увенчается успехом без предварительного усечения строки функцией Лев().Когда качество входящих данных непредсказуемо, вместо жесткого метода НайтиПоНаименованию надежнее использовать объект Запрос с оператором ПОДОБНО. Это позволяет игнорировать нетипичные пробельные разделители между словами:
ШаблонПоиска = СтрЗаменить(СокрЛП(СтрокаИзExcel), " ", "%");
ШаблонПоиска = СтрЗаменить(ШаблонПоиска, Символы.НПП, "%");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Спр.Ссылка КАК Ссылка
|ИЗ
| Справочник.ТипыПитания КАК Спр
|ГДЕ
| Спр.Наименование ПОДОБНО &ШаблонПоиска";
Запрос.УстановитьПараметр("ШаблонПоиска", "%" + ШаблонПоиска + "%");
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
НайденнаяСсылка = Выборка.Ссылка;
КонецЕсли;
Если пользователю требуется вручную перенести единичное наименование из Excel в 1С без попадания лишних переносов строк, рекомендуем следующий алгоритм: