Как сравнить два IP-адреса или версии в строковом формате в 1С

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

В процессе разработки в среде 1С:Предприятие 8 программисты часто сталкиваются с необходимостью сравнения строк, содержащих числовые сегменты, разделенные точками. Типичные примеры таких данных — IP-адреса (например, 245.120.243.567 и 299.125.40.69) или номера версий программного обеспечения (например, 8.3.24.1150 и 8.3.9.100). Попытка сравнить такие строки напрямую стандартными операторами сравнения приводит к логическим ошибкам. Выясним причину этой проблемы и разберем по шагам несколько надежных способов её решения.

Суть проблемы: почему стандартное сравнение строк не работает

Разберем ситуацию на простом примере. Предположим, нам нужно сравнить два IP-адреса: "192.168.1.2" и "192.168.1.10". Очевидно, что второй адрес с точки зрения сетевой логики больше первого. Однако в 1С при выполнении кода:


Если "192.168.1.2" > "192.168.1.10" Тогда
    // Этот код выполнится!
КонецЕсли;

Мы получим результат Истина. Платформа сравнивает строки лексикографически (посимвольно слева направо). Дойдя до 11-го символа, система сравнивает символ "2" с символом "1". Поскольку код символа «два» больше кода символа «один», первая строка признается большей, игнорируя дальнейшие знаки.

Попытка просто удалить точки из строки с помощью функции СтрЗаменить(), как предлагалось в некоторых сообщениях форума, также является ошибочной. В таком случае сравнение строки "222.22" (после удаления точек — 22222) и строки "222.022" (после удаления точек — 222022) покажет, что второе число больше, хотя математически это не так. Рассмотрим правильные подходы к решению этой задачи.

Способ 1. Приведение сегментов к фиксированной длине (нормализация строк)

Один из самых простых и красивых способов сравнения таких строк — приведение каждого числового сегмента между точками к фиксированной длине (например, до 3 символов) путем добавления ведущих нулей. После такой нормализации строки можно сравнивать стандартным оператором > или <.

Проанализируем алгоритм реализации этого метода:

  1. Разбиваем исходную строку в массив с помощью разделителя «точка».
  2. Для каждого элемента полученного массива применяем функцию форматирования, добавляя ведущие нули.
  3. Соединяем элементы массива обратно в строку.
  4. Сравниваем полученные нормализованные строки.

Посмотрим на практический пример реализации этого метода на языке 1С:


&НаКлиенте
Процедура СравнитьАдресаМетодомНормализации()
    IPСтрока1 = "245.120.243.567";
    IPСтрока2 = "299.125.40.69";
    
    НормализованныйIP1 = НормализоватьСтрокуIP(IPСтрока1);
    НормализованныйIP2 = НормализоватьСтрокуIP(IPСтрока2);
    
    Если НормализованныйIP1 > НормализованныйIP2 Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Первый IP-адрес больше");
    ИначеЕсли НормализованныйIP1 < НормализованныйIP2 Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Второй IP-адрес больше");
    Иначе
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Адреса равны");
    КонецЕсли;
КонецПроцедуры

&НаКлиентеБезКонтекста
Функция НормализоватьСтрокуIP(Знач ИсходныйАдрес)
    ЧастиАдреса = СтрРазделить(ИсходныйАдрес, ".");
    Для Индекс = 0 По ЧастиАдреса.ВГраница() Цикл
        // Приводим к числу и форматируем, задавая фиксированную ширину 3 символа с ведущими нулями
        ЧисловоеЗначение = Число(ЧастиАдреса[Индекс]);
        ЧастиАдреса[Индекс] = Формат(ЧисловоеЗначение, "ЧЦ=3; ЧВН=; ЧГ=0");
    КонецЦикла;
    Возврат СтрСоединить(ЧастиАдреса, ".");
КонецФункции

После нормализации наши строки примут вид "245.120.243.567" и "299.125.040.069". Сравнение таких строк вернет абсолютно корректный результат.

Способ 2. Покомпонентное сравнение элементов массива

Этот способ основан на разбиении обеих строк на массивы и поочередном сравнении элементов с одинаковыми индексами как чисел. Мы прекращаем сравнение, как только находим первый неравный элемент.

Разберем по шагам код реализации покомпонентного сравнения:


&НаКлиентеБезКонтекста
Функция СравнитьIPПокомпонентно(Знач IP1, Знач IP2)
    Массив1 = СтрРазделить(IP1, ".");
    Массив2 = СтрРазделить(IP2, ".");
    
    // Определяем минимальное количество итераций на случай разного числа сегментов
    КоличествоСегментов = Мин(Массив1.Количество(), Массив2.Количество());
    
    Для Индекс = 0 По КоличествоСегментов - 1 Цикл
        Число1 = Число(Массив1[Индекс]);
        Число2 = Число(Массив2[Индекс]);
        
        Если Число1 > Число2 Тогда
            Возврат 1; // Первая строка больше
        ИначеЕсли Число1 < Число2 Тогда
            Возврат -1; // Вторая строка больше
        КонецЕсли;
    КонецЦикла;
    
    // Если общие сегменты равны, больше та строка, у которой сегментов больше
    Если Массив1.Количество() > Массив2.Количество() Тогда
        Возврат 1;
    ИначеЕсли Массив1.Количество() < Массив2.Количество() Тогда
        Return -1;
    КонецЕсли;
    
    Возврат 0; // Строки полностью идентичны
КонецФункции

Способ 3. Использование готовых механизмов БСП

Если в вашей конфигурации внедрена Библиотека стандартных подсистем (БСП), вам вообще не требуется писать собственный программный код для разбора строк. В составе БСП присутствует готовая и протестированная функция, оптимизированная для клиент-серверного использования.

Рассмотрим применение стандартной функции общего модуля:


РезультатСравнения = ОбщегоНазначенияКлиентСервер.СравнитьВерсии("299.125.40.69", "245.120.243.567");

Если РезультатСравнения > 0 Тогда
    // Первая строка больше
ИначеЕсли РезультатСравнения < 0 Тогда
    // Вторая строка больше
Иначе
    // Строки эквивалентны
КонецЕсли;

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

Способ 4. Математический перевод IP-адреса в число (IP to Long)

Если на входе гарантированно присутствуют корректные IPv4-адреса (в которых каждое число находится в диапазоне от 0 до 255), наиболее производительным решением будет их перевод в единое 32-битное числовое значение.

Математическая формула перевода выглядит следующим образом:

Число = (Октет1 * 16777216) + (Октет2 * 65536) + (Октет3 * 256) + Октет4

Реализуем данный математический подход в коде 1С:


&НаКлиентеБезКонтекста
Функция IPАдресВЧисло(Знач СтрокаIP)
    Части = СтрРазделить(СтрокаIP, ".");
    Если Части.Количество() <> 4 Тогда
        Возврат 0; // Возвращаем 0 при неверном формате
    КонецЕсли;
    
    ЧисловойАдрес = Число(Части[0]) * 16777216 
                   + Число(Части[1]) * 65536 
                   + Число(Части[2]) * 256 
                   + Число(Части[3]);
                   
    Возврат ЧисловойАдрес;
КонецФункции

Этот метод незаменим, когда требуется выполнять частые операции сравнения или определять вхождение IP-адреса в заданный диапазон (например, принадлежит ли адрес определенной подсети).

Рекомендации по работе с IP-адресами в запросах 1С

Стоит отметить, что внутри запросов 1С невозможно использовать строковые функции разбора (такие как СтрРазделить) или обращаться к методам БСП. Если перед вами стоит задача выполнять сортировку или сравнение IP-адресов в динамических списках на управляемых формах или в отчетах СКД, рекомендуется использовать денормализацию данных при записи.

При записи элемента справочника или документа преобразуйте строковый IP-адрес в число (с помощью Способа 4) или в нормализованную строку с ведущими нулями (с помощью Способа 1) и записывайте это значение в отдельный реквизит базы данных (например, IPАдресЧислом или IPАдресНормализованный). В этом случае СУБД сможет мгновенно сортировать и сравнивать данные реквизиты стандартными методами платформы.

← На главную