В платформе 1С:Предприятие 7.7 встроенная функция Найти() является регистрозависимой. Это означает, что при поиске строки "иванов" в тексте "Иванов Иван Иванович" функция вернет 0, так как регистр первых букв не совпадает. В современных версиях платформы (8.х) в запросах эта проблема решается автоматически, но в "семерке" разработчикам приходится применять различные технические уловки. В этой статье мы подробно разберем, как обойти это ограничение, проанализируем производительность разных методов и выберем оптимальные решения для различных ситуаций.
Это самый простой и распространенный способ, который подходит для большинства задач, где объем обрабатываемых данных невелик. Суть метода заключается в том, чтобы перед поиском преобразовать и исходную строку, и искомую подстроку в один и тот же регистр (нижний или верхний).
Рассмотрим стандартный пример кода:
// Пример поиска без учета регистра
СтрокаГдеИщем = "Государственный Контракт №123";
ЧтоИщем = "контракт";
Если Найти(НРег(СтрокаГдеИщем), НРег(ЧтоИщем)) > 0 Тогда
Сообщить("Вхождение найдено!");
КонецЕсли;
Разберем, почему это работает. Функция НРег() (нижний регистр) переводит все буквы в строке в строчные. Таким образом, сравнение происходит между "государственный контракт №123" и "контракт", что позволяет функции Найти() успешно определить позицию вхождения. Аналогично можно использовать функцию ВРег() (верхний регистр).
Важное замечание по производительности: Нужно понимать, что функции НРег() и ВРег() создают в оперативной памяти новую копию строки. Если вы выполняете такой поиск в цикле по десяткам тысяч записей или обрабатываете очень длинные текстовые блоки (например, содержание больших файлов), это может привести к существенному замедлению работы системы и повышенному потреблению памяти.
Для того чтобы код выглядел чище и его было удобнее поддерживать, рекомендуется вынести логику сравнения в отдельные функции в глобальном модуле или модуле формы. Это позволит вам не задумываться о регистре каждый раз при написании алгоритмов.
Проанализируем пример таких функций:
// Функция для поиска вхождения без учета регистра
Функция НайтиРегНез(Строка1, Строка2)
Возврат Найти(НРег(Строка1), НРег(Строка2));
КонецФункции
// Функция для точного сравнения строк без учета регистра
Функция СравнитьРегНез(Строка1, Строка2)
Возврат ?(НРег(Строка1) = НРег(Строка2), 1, 0);
КонецФункции
Использование таких "оберток" делает ваш код более читаемым и позволяет быстро изменить логику сравнения во всей конфигурации, если это потребуется (например, при переходе на другие методы поиска).
Если вам необходимо выполнять поиск в больших текстах или использовать сложные условия (например, поиск по маске), лучшим решением будет использование COM-объекта VBScript.RegExp. Этот объект работает на уровне операционной системы и позволяет выполнять поиск без учета регистра гораздо эффективнее, чем стандартные строковые функции 1С 7.7.
Разберем по шагам, как это реализовать:
VBScript.RegExp.IgnoreCase в значение 1 (игнорировать регистр).Pattern.Test() для проверки наличия или Execute() для получения позиции.
// Пример использования регулярных выражений
RegExp = СоздатьОбъект("VBScript.RegExp");
RegExp.IgnoreCase = 1; // Игнорировать регистр
RegExp.Global = 0;
RegExp.Pattern = "контракт";
ТекстДляПоиска = "Работа с ГосКонтрактами требует внимания.";
Если RegExp.Test(ТекстДляПоиска) = -1 Тогда
Сообщить("Найдено с помощью RegExp!");
КонецЕсли;
Этот метод не создает лишних копий строк в памяти 1С, так как обработка текста происходит внутри внешнего компонента, что положительно сказывается на скорости работы в сложных алгоритмах.
Для баз данных, работающих на MS SQL Server, проблему регистра можно решить на уровне самого сервера. Если вы используете внешние компоненты, такие как 1С++ или Rainbow, вы можете выполнять прямые запросы к таблицам базы данных.
В большинстве случаев базы данных 1С 7.7 создаются с кодировкой (Collation), которая уже настроена как Case Insensitive (CI). Это означает, что оператор LIKE в SQL-запросе найдет данные независимо от того, какими буквами они написаны.
Пример логики запроса:
// Примерный SQL-текст для использования через 1С++
ТекстЗапроса = "
|SELECT *
|FROM $Справочник.Клиенты as Клиенты
|WHERE Клиенты.Наименование LIKE '%иванов%'
|";
Такой запрос найдет и "Иванов", и "ИВАНОВ", и "иванов". Это самый быстрый способ поиска, если вам нужно отфильтровать список элементов в справочнике или документов по строковому реквизиту.
В ситуациях, когда требуется мгновенный поиск по большим объемам текстовой информации (например, поиск по комментариям в справочнике номенклатуры), можно применить метод предварительной индексации. Выясним причину, почему это эффективно: мы переносим нагрузку с момента поиска на момент записи данных.
Проанализируем ситуацию: мы можем создать дополнительный скрытый реквизит (индексированный) или отдельную таблицу, куда при записи объекта будем сохранять все слова из целевого текста, приведенные к верхнему регистру. Тогда поиск будет сводиться к простому запросу по индексу, что происходит практически мгновенно даже в огромных базах данных.
При реализации поиска без учета регистра в 1С 7.7 программисты часто сталкиваются с проблемой буквы "Ё". Функции НРег() и ВРег() в некоторых сборках платформы могут некорректно обрабатывать эту букву или считать её отличной от "Е".
Совет: Если ваш поиск должен быть максимально лояльным к пользователю, перед сравнением строк рекомендуется выполнить замену всех символов "ё" на "е". Это гарантирует, что поиск найдет "Семёнов", даже если пользователь ввел "семенов".
// Пример нормализации строки перед поиском
Стр = СтрЗаменить(НРег(ИсходнаяСтрока), "ё", "е");
Подстрока = СтрЗаменить(НРег(ИскомаяПодстрока), "ё", "е");
Если Найти(Стр, Подстрока) > 0 Тогда
// Найдено!
КонецЕсли;
Для выбора метода поиска воспользуйтесь следующими рекомендациями:
НРег().