Почему в 1С сравнение строк Вася = вася возвращает Ложь и как правильно сравнивать строки?

Программист IT и автоматизация бизнеса
← На главную

В практике разработчика 1С часто возникает ситуация, когда код, основанный на сравнении строковых данных, начинает вести себя непредсказуемо. Одной из самых распространенных причин путаницы является различие в логике работы встроенного языка и языка запросов при сопоставлении строк с разным регистром символов. Рассмотрим детально, почему выражение "Вася" = "вася" может возвращать разные результаты в зависимости от контекста выполнения, и разберем лучшие практики решения этой задачи.

Различие между встроенным языком и языком запросов

Первое и самое важное правило, которое нам необходимо усвоить: встроенный язык 1С всегда чувствителен к регистру при использовании операторов сравнения (=, <>). Если мы выполняем проверку непосредственно в программном коде модуля, то символы "В" и "в" будут считаться абсолютно разными объектами из-за различия их кодов в таблице символов.

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


Если "Вася" = "вася" Тогда
    // Этот блок никогда не выполнится
    Сообщить("Строки равны");
Иначе
    // Программа всегда зайдет сюда
    Сообщить("Строки не равны");
КонецЕсли;

В то же время, если мы напишем запрос к базе данных, поведение системы кардинально изменится. Язык запросов 1С по умолчанию нечувствителен к регистру. Это связано с тем, что физические СУБД (MS SQL Server, PostgreSQL), на которых работает 1С, настраиваются платформой с использованием определенных параметров сопоставления (Collation).

Посмотрим на пример запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	""Равны"" КАК Результат
    |ГДЕ
    |	""Вася"" = ""вася""";

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    // Запрос вернет строку "Равны"
КонецЕсли;

Такое расхождение часто приводит к ошибкам: разработчик проверяет условие в консоли запросов, видит, что данные находятся, а затем пишет аналогичное условие в коде на встроенном языке, и оно перестает работать.

Использование функций приведения регистра: ВРег и НРег

Чтобы выполнить регистронезависимое сравнение во встроенном языке, мы должны явно привести обе строки к одному регистру — либо к верхнему, либо к нижнему. Для этого используются функции ВРег() (Верхний Регистр) и НРег() (Нижний Регистр).

Разберем, как правильно модифицировать проверку:


// Приведение к верхнему регистру
Если ВРег("Вася") = ВРег("вася") Тогда
    Сообщить("Теперь строки равны, так как обе стали 'ВАСЯ'");
КонецЕсли;

// Приведение к нижнему регистру
Если НРег("Вася") = НРег("вася") Тогда
    Сообщить("Теперь строки равны, так как обе стали 'вася'");
КонецЕсли;

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

Современный подход: Функция СтрСравнить

Начиная с версии платформы 8.3.10, в распоряжении программистов появился более изящный и мощный инструмент — функция СтрСравнить(). Она позволяет сравнивать строки без создания промежуточных копий строк в памяти, которые неизбежны при использовании ВРег().

Рассмотрим синтаксис этой функции:

СтрСравнить(Строка1, Строка2, ВариантСравненияСтрок.ИгнорироватьРегистр)

Преимущества использования СтрСравнить:

  1. Производительность: Платформа выполняет сравнение на низком уровне без лишних преобразований данных.
  2. Читаемость: Намерение разработчика (игнорировать регистр) выражено явно через параметр.
  3. Локализация: Функция корректно обрабатывает правила национальных алфавитов.

Влияние регистронезависимости на производительность запросов

Важно помнить о нюансах работы СУБД. Хотя в запросах 1С сравнение ГДЕ Поле = "значение" не учитывает регистр, попытка принудительно использовать функцию ВРЕГ() внутри запроса может фатально замедлить работу системы.

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


// ОПАСНО ДЛЯ ПРОИЗВОДИТЕЛЬНОСТИ
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура ГДЕ ВРЕГ(Наименование) = &П_НаименованиеВВерхнемРегистре";

В этом случае СУБД не сможет использовать индекс по полю Наименование, так как она обязана сначала применить функцию к каждой строке таблицы, а только потом сравнивать. Это приведет к полному сканированию таблицы (Table Scan). Поскольку запросы в 1С и так нечувствительны к регистру, дополнительные преобразования в секции ГДЕ излишни.

Особенности Юникода и визуально похожие символы

Иногда возникают ситуации, когда даже ВРег() не помогает. Выясним причину этого явления. Проблема может крыться в использовании символов из разных раскладок, которые выглядят идентично (например, латинская "C" и кириллическая "С").

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


Строка1 = "С"; // Кириллица
Строка2 = "C"; // Латиница
Если ВРег(Строка1) = ВРег(Строка2) Тогда
    // Сюда программа НЕ зайдет
КонецЕсли;

Для решения таких проблем при загрузке данных из внешних источников (Excel, CSV) рекомендуется предварительно обрабатывать строки, заменяя похожие латинские символы на кириллические или наоборот.

Также стоит учитывать особенности композитных символов в Юникоде. Один и тот же визуальный символ (например, "ё") может быть представлен в памяти либо как один код, либо как комбинация буквы "е" и диакритического знака "двоеточие сверху". С точки зрения 1С это будут разные строки. В таких случаях может потребоваться нормализация строк, хотя в стандартных бизнес-задачах это встречается редко.

Поведение NULL в запросах и коде

В ходе обсуждения важно также затронуть тему сравнения неопределенных значений, так как это часто идет рука об руку со сравнением строк. Во встроенном языке 1С NULL = NULL всегда вернет Истина. Однако в языке запросов (SQL) результат любого сравнения с NULL (даже NULL = NULL) дает результат UNKNOWN, что в логике фильтрации приравнивается к Ложь.

Для проверки на пустое значение в запросах всегда используйте конструкцию ЕСТЬ NULL или IS NULL, вместо обычного равенства.

Подведение итогов

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

Таким образом, понимание архитектуры 1С и механизмов работы используемой СУБД позволяет избежать досадных ошибок "исчезающих данных" и писать надежный программный код.

← На главную