Почему функция СтрНайти в 1С не находит подстроку в визуально одинаковом тексте?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработчика 1С часто встречается загадочная ситуация: мы видим в отладчике две абсолютно идентичные строки, но функция СтрНайти (или Найти) упорно возвращает 0. Особенно часто это происходит при обработке данных, полученных из внешних систем: банковских выписок, Excel-файлов, PDF-документов или веб-сервисов. Давайте вместе разберем эту проблему, выясним скрытые причины и выработаем надежный алгоритм поиска.

Разберем типичный пример проблемы

Представим ситуацию, описанную в теме: у нас есть строка назначения платежа:

"(08-08) Перечисление заработной платы за 07.2018г. на б/к сотрудников согласно реестру №..."

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

Причина 1: Невидимые «пробельные» символы

Самая распространенная причина — использование разных типов пробелов. В 1С стандартный пробел имеет код 32. Однако при копировании из текстов или банковских программ часто попадает «неразрывный пробел» (NBSP), код которого 160. Визуально они неразличимы, но для системы это разные символы.

Рассмотрим, как очистить строку от таких символов перед поиском:


// Удаляем стандартный неразрывный пробел
ПодстрокаПоиска = СтрЗаменить(ПодстрокаПоиска, Символы.НПП, " ");
ТекстИсточника = СтрЗаменить(ТекстИсточника, Символы.НПП, " ");

// Выполняем поиск после очистки
Позиция = СтрНайти(ТекстИсточника, ПодстрокаПоиска);

Однако существуют и более экзотические варианты, такие как «узкий неразрывный пробел» (код 8239) или «нулевой пробел» (код 8203). Если обычная замена Символы.НПП не помогает, проанализируем строку посимвольно.

Причина 2: Латинские буквы-двойники (Омографы)

Это классическая «ловушка» при ручном вводе или некорректном распознавании текста. Некоторые буквы кириллицы выглядят в точности как латинские: «а», «е», «о», «р», «с», «у», «х». Если в слове «Перечисление» первая буква «П» кириллическая, а «е» случайно введена на английской раскладке, СтрНайти не найдет совпадения.

Чтобы проверить это, воспользуемся функцией КодСимвола в цикле. Давайте посмотрим на пример кода для диагностики:


Для Индекс = 1 По СтрДлина(ПодозрительнаяСтрока) Цикл
    Символ = Сред(ПодозрительнаяСтрока, Индекс, 1);
    Сообщить("Символ: " + Символ + " Код: " + КодСимвола(Символ));
КонецЦикла;

Если вы видите коды в диапазоне 65-122 для русских слов — перед вами латиница.

Причина 3: Регистр символов

Функция СтрНайти может быть чувствительна к регистру в зависимости от настроек базы данных (SQL Collation). Чтобы гарантированно избежать ошибок, всегда приводите обе строки к одному регистру, обычно к нижнему.

Проанализируем правильный подход к поиску:

Позиция = СтрНайти(НРег(ТекстИсточника), НРег(ПодстрокаПоиска));

Причина 4: Скрытые символы форматирования и Unicode-нормализация

Существуют символы, которые вообще не отображаются в конфигураторе 1С:

  1. Мягкий перенос (Soft Hyphen, код 173): он может разрывать слово внутри, делая его невидимым для поиска.
  2. Диакритические знаки: Буква «й» может быть записана как один символ (код 1081) или как комбинация «и» + «кратка» сверху. Визуально это одна буква, но байты разные.
  3. Спецсимволы банковских систем: При загрузке выписок из текстовых файлов в кодировке OEM-866 могут возникать артефакты преобразования.

Продвинутые методы решения задачи

Если стандартные методы не помогают, рассмотрим более радикальные, но эффективные способы.

Метод 1: Очистка «Только значимые символы»

Мы можем создать вспомогательную функцию, которая оставляет в строке только буквы и цифры, заменяя всё остальное на пробелы или вовсе удаляя. Это позволит игнорировать любые виды пробелов, тире и переносов.


Функция ОчиститьСтрокуДляПоиска(Знач ВхСтрока)
    Результат = "";
    ДопустимыеСимволы = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя0123456789 ";
    ВхСтрока = НРег(ВхСтрока);
    
    Для К = 1 По СтрДлина(ВхСтрока) Цикл
        Символ = Сред(ВхСтрока, К, 1);
        Если СтрНайти(ДопустимыеСимволы, Символ) > 0 Тогда
            Результат = Результат + Символ;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Метод 2: Использование Регулярных выражений

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

Выясним, как это упрощает жизнь:


// Ищем фразу, где между словами может быть любое количество пробельных символов
Шаблон = "Перечисление\s+заработной\s+платы"; 
Результат = СтрНайтиПоРегулярномуВыражению(ТекстИсточника, Шаблон);

Если ваша платформа ниже 8.3.24, можно использовать объект VBScript.RegExp через COM-соединение.

Рекомендации по профилактике

Чтобы подобные ошибки не возникали в будущем, придерживайтесь следующих правил:

  1. Всегда нормализуйте входные данные: При загрузке из внешних файлов делайте замену Символы.НПП на обычные пробелы.
  2. Используйте функции приведения регистра: НРег() — ваш лучший друг при сравнении строк.
  3. Проверяйте параметры поиска: Убедитесь, что в функции СтрНайти третий параметр (НачальнаяПозиция) не установлен случайно в значение больше 1.
  4. Сравнивайте по частям: Если длинная фраза не ищется, попробуйте найти уникальное ключевое слово из нее (например, только "заработной").

Подводя итог, можно сказать: чудес в программировании не бывает. Если 1С говорит, что подстроки нет — значит, на уровне кодов символов строки действительно различаются. Использование посимвольного анализа через КодСимвола — самый быстрый способ найти "виновника" и устранить проблему раз и навсегда.

← На главную