Как реализовать буквенную нумерацию (A, B, ..., Z, AA, AB) в 1С по аналогии с Excel

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

При разработке механизмов обмена данными, формировании печатных форм или создании уникальных идентификаторов программисты часто сталкиваются с задачей генерации последовательностей, использующих буквы латинского алфавита. Самый известный пример такой системы — наименование колонок в таблицах Excel: сначала идут одиночные буквы от A до Z, затем двухбуквенные комбинации AA, AB... AZ, затем BA и так далее. Рассмотрим, как реализовать этот механизм в 1С и в чем заключаются математические особенности такой нумерации.

Суть проблемы: почему обычный перевод в систему счисления не подходит

На первый взгляд кажется, что перед нами обычная 26-ричная система счисления, где буквам A-Z соответствуют цифры 0-25. Однако при попытке стандартного перевода мы столкнемся с проблемой "ведущего нуля". Проанализируем ситуацию: в позиционных системах счисления (например, десятичной) числа 0, 00 и 000 математически равны. Если мы назначим букву A нулем, то последовательности A, AA и AAA будут означать одно и то же число, что недопустимо для уникальной маркировки.

Эта специфическая последовательность называется биективной системой счисления с основанием 26. В ней отсутствует символ «ноль», а каждое натуральное число (1, 2, 3...) соответствует строго одной уникальной строке символов. Рассмотрим подробнее, как это реализовать программно.

Алгоритм формирования буквенного суффикса

Разберем по шагам логику, которая позволяет правильно переходить от числа к буквенному представлению. Ключевым моментом здесь является "сдвиг" на единицу при расчете остатка. Проанализируем код функции, предложенный в обсуждении:


Функция НомерДляМаркировки(Знач Значение = 0, Нотация = 26, СтрокаСистемы = "ABCDEFGHIJKLMNOPQRSTUVWXYZ") Экспорт
    // 1 -> A
    // 26 -> Z
    // 27 -> AA
    Результат = "";
    
    Пока Значение > 0 Цикл
        // Вычисляем символ текущего разряда со сдвигом
        Результат = Сред(СтрокаСистемы, (Значение - 1) % Нотация + 1, 1) + Результат;
        
        Если Значение <= Нотация Тогда
            Прервать;
        КонецЕсли;
        
        // Уменьшаем значение для перехода к следующему разряду
        Значение = Цел((Значение - 1) / Нотация);
        
        Если Значение = 0 Тогда 
            Прервать; 
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Выясним причину использования конструкции (Значение - 1). Именно это вычитание позволяет нам корректно обрабатывать границы разрядов. Например, когда Значение равно 26, операция (26-1) % 26 + 1 даст нам 26-й символ алфавита (Z). Без этого вычитания остаток от деления 26 на 26 был бы равен 0, что характерно для классических систем счисления, но ломает логику Excel-подобных рядов.

Сравнение с классическим переводом в систему счисления

Посмотрим на пример, как ведет себя обычная функция перевода (где A=0, B=1... BA=26):

Как мы видим, в классическом варианте число 26 превращается в BA (аналог 10 в десятичной системе), пропуская AA. В нашей же задаче 26 должно быть Z, а 27 — AA. Рассмотрим результаты работы правильного алгоритма:

Альтернативный подход с использованием степеней

Проанализируем еще один способ реализации, который опирается на предварительное вычисление количества знаков в итоговой строке. Этот метод удобен, если нужно четко понимать, сколько "ячеек" займет номер.


Функция ПолучитьБуквенныйКод(Знач ЧислоДляПеревода) Экспорт
    Модуль = 26;
    НачКод = КодСимвола("A");
    
    // Определяем количество цифр (разрядов)
    КоличествоРазрядов = 1;
    Пока ЧислоДляПеревода >= Pow(Модуль, КоличествоРазрядов) Цикл
        // В биективной системе каждый новый разряд "съедает" объем комбинаций предыдущих
        ЧислоДляПеревода = ЧислоДляПеревода - Pow(Модуль, КоличествоРазрядов); 
        КоличествоРазрядов = КоличествоРазрядов + 1;
    КонецЦикла;
    
    Результат = "";
    Для Инд = 1 По КоличествоРазрядов Цикл
        Результат = Символ(НачКод + ЧислоДляПеревода % Модуль) + Результат;
        ЧислоДляПеревода = Цел(ЧислоДляПеревода / Модуль);
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

В данном примере мы используем встроенные функции 1С КодСимвола и Символ, что избавляет от необходимости хранить строку-алфавит. Это решение более изящно с точки зрения использования ресурсов платформы.

Практическое применение в задачах 1С

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

Основные области применения:

  1. Генерация имен колонок: При программном формировании файлов Excel через COM-объект или при записи в ТабличныйДокумент для обращения к области.
  2. Уникальные суффиксы: Когда длина поля ограничена, а количество повторов велико (буквенная система гораздо компактнее десятичной: 2 символа дают 676 комбинаций вместо 100).
  3. Генерация промокодов: Создание коротких буквенных последовательностей для идентификации скидок или акций.
  4. Секционные индексы: Маркировка разделов в сложных отчетах.

Важно помнить, что если вы используете эту систему для формирования имен файлов или элементов справочников, стоит учитывать регистр символов и возможность расширения алфавита (например, использование цифр и букв одновременно), что превратит систему в биективную 36-ричную систему. Принцип реализации при этом останется неизменным — главное соблюдать правило сдвига на единицу при расчете каждого разряда.

← На главную