В практике разработчика 1С часто возникает загадочная ситуация: при отладке две строковые переменные выглядят абсолютно идентичными, но логическое выражение ТекЗначение = ЗначениеТекст возвращает Ложь. Попытки принудительного преобразования типов или использования функции СокрЛП() часто не приносят результата. Проанализируем, почему так происходит, и разберем по шагам методику поиска "невидимых" виновников этой проблемы.
Основная причина такого поведения кроется в наличии спецсимволов, которые не имеют визуального представления в графическом интерфейсе 1С (в табло отладчика или в полях ввода), но учитываются платформой при сравнении. Платформа 1С выполняет строгое сравнение строк по кодам символов Unicode. Если хотя бы один код в последовательности отличается — строки не будут равны.
Чаще всего такие символы попадают в базу при:
Первое, что мы сделаем — проверим длину обеих строк. Если строки визуально одинаковы, но функция СтрДлина() возвращает разные значения, значит, в одной из них точно есть лишний символ. Рассмотрим простой пример:
Сообщить("Длина 1: " + СтрДлина(ТекЗначение));
Сообщить("Длина 2: " + СтрДлина(ЗначениеТекст));
Если длины различаются, наша задача упрощается — нужно найти позицию лишнего символа. Но бывает и так, что длины одинаковы, а сравнение все равно выдает Ложь. Это означает, что в строках на одной и той же позиции стоят разные символы, которые выглядят одинаково (например, латинская "o" вместо кириллической "о").
Чтобы гарантированно найти различие, разберем метод посимвольного сравнения. Мы будем использовать функции Сред() для получения конкретного знака и КодСимвола() для получения его числового кода в кодировке Unicode. Проанализируем следующий алгоритм:
Длина1 = СтрДлина(ТекЗначение);
Длина2 = СтрДлина(ЗначениеТекст);
МаксДлина = Макс(Длина1, Длина2);
Для К = 1 По МаксДлина Цикл
Символ1 = Сред(ТекЗначение, К, 1);
Символ2 = Сред(ЗначениеТекст, К, 1);
Код1 = ?(К <= Длина1, КодСимвола(Символ1), "отсутствует");
Код2 = ?(К <= Длина2, КодСимвола(Символ2), "отсутствует");
Если Код1 <> Код2 Тогда
Сообщить("Различие в позиции " + К);
Сообщить("Строка 1: '" + Символ1 + "' код: " + Код1);
Сообщить("Строка 2: '" + Символ2 + "' код: " + Код2);
КонецЕсли;
КонецЦикла;
Этот код позволяет выявить скрытые символы, даже если они находятся в начале или в конце строки. Именно так можно обнаружить коварный символ с кодом 8203.
Рассмотрим подробнее, какие именно коды символов чаще всего мешают нам жить:
СокрЛП() его не удаляет, так как он не является стандартным пробелом (код 32).Проанализируем, как можно автоматизировать очистку строк. Если мы выяснили, что мешает конкретный символ (например, 8203), мы можем использовать функцию СтрЗаменить().
Если мы точно знаем код вредоносного символа, воспользуемся функцией Символ():
// Удаляем пробел нулевой ширины
ТекЗначение = СтрЗаменить(ТекЗначение, Символ(8203), "");
// Удаляем неразрывные пробелы, заменяя их на обычные
ТекЗначение = СтрЗаменить(ТекЗначение, Символ(160), " ");
ТекЗначение = СокрЛП(ТекЗначение);
Для надежной работы при загрузке из внешних источников рекомендуется создать общую функцию, которая будет "просеивать" строку от всех нежелательных элементов. Посмотрим на пример такой функции:
Функция ОчиститьСтрокуОтМусора(Знач ИсходнаяСтрока) Экспорт
// Удаляем невидимые спецсимволы
ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символ(8203), ""); // Zero-width space
ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символ(65279), ""); // BOM
// Заменяем неразрывные пробелы на обычные для корректной работы СокрЛП
ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символ(160), " ");
// Убираем управляющие символы (0-31)
Для Код = 0 По 31 Цикл
ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символ(Код), "");
КонецЦикла;
Возврат СокрЛП(ИсходнаяСтрока);
КонецФункции
Существует еще один способ "увидеть" скрытое, не прибегая к циклам. Рассмотрим преобразование строки в XML. В формате XML многие спецсимволы заменяются на их числовые сущности. Посмотрим на пример кода:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписьXML.ЗаписатьТекст(ЗначениеТекст);
РезультатXML = ЗаписьXML.Закрыть();
Сообщить(РезультатXML);
Если в строке был символ 8203, в результате вы увидите нечто вроде ​. Это отличный способ быстрой визуальной диагностики без написания сложных обработок.
Мы выяснили, что равенство строк в 1С — это не только визуальное сходство, но и полное совпадение кодов всех знаков. При работе с внешними данными (Excel, Web) всегда стоит проявлять бдительность. Рекомендуется внедрять превентивную очистку строк от символов 160 и 8203 еще на этапе загрузки, чтобы избежать трудноуловимых ошибок в бизнес-логике программы.