Число по цифрам в 1С: деление с остатком и разбор строки
Содержание
Разложить число на отдельные цифры во встроенном языке 1С можно двумя путями: арифметикой — через остаток от деления % 10 и целую часть Цел(), или строкой — перевести число в текст и обойти его посимвольно функцией Сред(). Оба дают на выходе набор цифр; разница в скорости и в том, что удобнее дописывать под задачу.
Арифметику берут, когда нужны именно числа для расчёта (сумма разрядов, контрольная цифра). Строку — когда важен порядок символов и не жаль пары лишних миллисекунд. Ниже — рабочий код для обоих, плюс то, обо что чаще всего спотыкаются: отрицательные значения, ноль, дробная часть и коварный разделитель групп.
Деление с остатком: достаём цифры арифметикой
Идея простая. Остаток от деления на 10 — это последняя цифра числа. Отбросили её целочисленным делением на 10 — и повторяем, пока число не обнулится.
Во встроенном языке за это отвечают два инструмента:
- 🔢
Число % 10— остаток от деления, то есть младший разряд (12345 % 10=5); - ✂️
Цел(Число / 10)— целая часть от деления на 10, то есть «число без последней цифры» (Цел(12345 / 10)=1234).
Цикл разбора выглядит так:
Число = 12345;
Пока Число > 0 Цикл
Цифра = Число % 10; // 5, затем 4, 3, 2, 1
Сообщить(Цифра);
Число = Цел(Число / 10); // 1234, 123, 12, 1, 0
КонецЦикла;
Цифры выходят с конца: сначала 5, потом 4 и так до 1. Если нужен естественный порядок слева направо, не разворачивайте результат отдельным циклом — вставляйте каждую цифру в начало массива:
Массив = Новый Массив;
Пока Число > 0 Цикл
Массив.Вставить(0, Число % 10); // всегда в начало
Число = Цел(Число / 10);
КонецЦикла;
Вставить(0, Значение) добавляет элемент по индексу 0, сдвигая остальные. Для 12345 получаем массив [1, 2, 3, 4, 5] в правильном порядке.
Способ работает только с целой частью. Дробь он молча игнорирует: Цел(12.7 / 10) отбросит всё после запятой на первом же шаге. Как разобрать дробную часть — ниже, в разделе про особые случаи.
Через строку: преобразование и посимвольный обход
Второй путь — превратить число в строку и пройти по символам. Читается нагляднее, и порядок цифр сразу правильный, слева направо.
Но здесь прячется главная ловушка. Прямое Строка(12345) вернёт не "12345", а "12 345" — с неразрывным пробелом как разделителем групп разрядов. Посимвольный обход тогда наткнётся на пробел, а Число(" ") даст ноль или ошибку.
Для перевода числа в строку используйте Формат с параметром ЧГ=0 — он отключает разделитель групп.
Число = 12345;
Стр = Формат(Число, "ЧГ=0"); // "12345", без пробелов
Массив = Новый Массив;
Для Поз = 1 По СтрДлина(Стр) Цикл
Символ = Сред(Стр, Поз, 1); // по одному символу
Массив.Добавить(Число(Символ)); // "1" -> 1
КонецЦикла;
Что здесь что:
Формат(Число, "ЧГ=0")— число в строку без форматирования разрядов;СтрДлина(Стр)— количество символов;Сред(Стр, Поз, 1)— один символ начиная с позицииПоз(нумерация с 1);Число(Символ)— обратно в числовой тип, если нужна именно цифра, а не знак.
Если цифры нужны как текст (например, для вывода в макет), Число(Символ) можно опустить и складывать в массив сами символы.
Формат(Число, "ЧГ=0") для дробного числа сохранит разделитель целой и дробной части (запятую или точку). Для работы только с целой частью сначала примените Цел(), иначе запятая попадёт в массив как отдельный символ.
Отрицательные числа, ноль и дробная часть
Три случая, на которых падает «наивный» код, если про них не подумать заранее.
Знак «минус». У отрицательного числа % 10 и деление ведут себя иначе, а в строке впереди появится символ -. Проще всего убрать знак в самом начале. Отдельной функции модуля в языке нет — используйте условие:
Число = ?(Число < 0, -Число, Число); // модуль числа
?(Условие, ТогдаЗначение, ИначеЗначение) — тернарный оператор: вернёт -Число, если число меньше нуля, и само число в остальных случаях.
Ноль. Цикл Пока Число > 0 для нуля не выполнится ни разу — массив останется пустым. Если 0 должен давать одну цифру 0, обработайте его явно до цикла:
Если Число = 0 Тогда
Массив.Добавить(0);
Возврат Массив;
КонецЕсли;
Дробная часть. Решите заранее, что с ней делать:
- 🧹 цифры нужны только из целой части — отбросьте дробь через
Цел(Число); - 🔍 нужны и цифры после запятой — удобнее строковый способ: переведите число в строку с
Формат(Число, "ЧРД=.")(точка как разделитель), разбейте по этому разделителю черезСтрРазделить, и разбирайте целую и дробную части по отдельности.
Жёстко прибивать точность (например, два знака после запятой) лучше тоже форматом: Формат(Число, "ЧДЦ=2; ЧРД=.; ЧГ=0"). Так вы не зависите от того, сколько знаков реально хранится в переменной.
Ведущие нули. Числовой тип их не хранит: 007 и 7 для 1С — одно и то же число, разбор даст [7]. Если ведущие нули значимы (табельный номер, артикул, код из файла обмена), не превращайте значение в число вообще — храните и разбирайте его как строку. Для фиксированной длины с нулями слева используйте формат Формат(Число, "ЧЦ=5; ЧВН=; ЧГ=0") — получите строку "00007".
Универсальная функция: цифры числа в массив
Собираем всё вместе — модуль, ноль, порядок слева направо. Функция возвращает массив цифр целой части любого числа.
Функция ЦифрыЧисла(Знач Число) Экспорт
Массив = Новый Массив;
// модуль и только целая часть
Число = Цел(?(Число < 0, -Число, Число));
Если Число = 0 Тогда
Массив.Добавить(0);
Возврат Массив;
КонецЕсли;
Пока Число > 0 Цикл
Массив.Вставить(0, Число % 10);
Число = Цел(Число / 10);
КонецЦикла;
Возврат Массив;
КонецФункции
Проверка на примерах:
| Вход | Результат |
|---|---|
12345 | [1, 2, 3, 4, 5] |
-408 | [4, 0, 8] |
0 | [0] |
70.9 | [7, 0] |
Параметр объявлен как Знач Число — значит, внутри функции мы меняем локальную копию, а переменная вызывающего кода остаётся нетронутой. Без Знач вы бы обнулили исходное число у вызывающей стороны.
Если на выходе нужны не числа, а строка из цифр подряд ("12345") — замените тело на строковый способ из второго раздела и возвращайте Формат(Цел(Число), "ЧГ=0").
Когда нужна не вся разбивка, а одна цифра на известной позиции, полный цикл не нужен. Комбинация деления и остатка достаёт конкретный разряд:
Единицы = Число % 10; // младший разряд
Десятки = Цел(Число / 10) % 10; // второй справа
Сотни = Цел(Число / 100) % 10; // третий справа
Для 4728: единицы — 8, десятки — 2, сотни — 7. Общая формула разряда: делим на 10 в нужной степени и берём остаток от деления на 10. Это дешевле, чем собирать весь массив ради одной цифры.
Какой из двух способов брать под конкретную задачу:
Формат(Число, "ЧГ=0"). Нагляднее, легче достать знаки после запятой.Сред() — не переводите строку в число и обратно, лишний шаг.Что быстрее: сравнение двух способов
На единичных вызовах разницы вы не заметите — оба способа отрабатывают за доли миллисекунды. Она проявляется в циклах на десятки и сотни тысяч чисел: массовая обработка, формирование больших печатных форм, проверка номеров при загрузке.
| Критерий | Деление с остатком | Через строку |
|---|---|---|
| Скорость в массовых циклах | Выше: только арифметика | Ниже: перевод в строку + Сред() |
| Читаемость | Чуть сложнее | Нагляднее |
| Дробная часть | Требует отдельной логики | Достаётся из строки проще |
| Исходник — строка | Нужен лишний перевод в число | Работает напрямую |
Практический вывод: в горячем цикле на большом объёме используйте арифметику, в разовых операциях и отчётах — тот способ, который понятнее поддерживать.
Отдельно про то, что реально тормозит, а не кажется: не вызывайте Формат() и не создавайте новый массив там, где можно обойтись. Если нужна только сумма цифр — не собирайте массив вовсе, складывайте остатки прямо в цикле. Лишняя коллекция на каждой итерации дороже самой арифметики.
Где это нужно на практике
Разбор числа на цифры — не самоцель, а шаг в типовых задачах. Четыре частых сценария.
Сумма цифр и контрольные разряды. Классика — проверка контрольного числа в кодах (номера документов, идентификаторы). Складываем цифры прямо в цикле, без массива:
Функция СуммаЦифр(Знач Число)
Число = Цел(?(Число < 0, -Число, Число));
Сумма = 0;
Пока Число > 0 Цикл
Сумма = Сумма + Число % 10;
Число = Цел(Число / 10);
КонецЦикла;
Возврат Сумма;
КонецФункции
Для 1234 функция вернёт 10 (1 + 2 + 3 + 4). На этой же механике строят алгоритмы проверки идентификаторов, где каждую цифру умножают на свой весовой коэффициент.
Сумма прописью. Чтобы перевести число в текст, его режут на триады (группы по три разряда справа) и обрабатывают каждую. Поразрядный разбор — основа таких алгоритмов, хотя для готовой суммы прописью в типовых конфигурациях есть штатная функция.
Маскирование номеров. Показать только последние цифры, остальные скрыть — например, в логах или на форме. Удобнее строкой: берём хвост через Прав(), начало заменяем на звёздочки:
Стр = Формат(Номер, "ЧГ=0");
Хвост = Прав(Стр, 4); // последние 4 цифры
Маска = СтрПовторить("*", СтрДлина(Стр) - 4); // звёзды на остальное
Результат = Маска + Хвост; // "************1234"
СтрПовторить("*", N) повторяет символ N раз, Прав(Стр, 4) берёт последние четыре символа. Для короткого номера (4 символа и меньше) добавьте проверку, иначе длина маски уйдёт в отрицательное число.
Поразрядный вывод в макет. Когда каждую цифру суммы нужно вывести в отдельную ячейку (бланки, квитанции), массив цифр из универсальной функции ложится прямо в область макета по одному элементу на колонку.
Для готовых задач не изобретайте велосипед: сумма прописью, форматирование разрядов и округление уже решены функциями Формат, Окр и библиотечными методами. Ручной разбор на цифры нужен там, где логика нестандартная.
Частые вопросы
Почему `Строка(Число)` даёт пробел между цифрами?
Формат(Число, "ЧГ=0") — параметр ЧГ=0 отключает группировку.Как получить цифры в обычном порядке, а не с конца?
Вставить(0, Цифра) — тогда порядок будет естественным, слева направо, без разворота.Есть ли в 1С функция модуля числа?
Abs во встроенном языке нет. Модуль получают условием: ?(Число < 0, -Число, Число). Для разбора на цифры знак обычно убирают в самом начале.Что делать с дробной частью?
Цел(Число). Если важны и знаки после запятой — переведите число в строку с фиксированной точностью (Формат(Число, "ЧДЦ=2; ЧРД=.")) и разберите целую и дробную части отдельно.Какой способ быстрее на больших объёмах?
Сред(). На единичных числах разница незаметна, в циклах на сотни тысяч элементов — ощутима.Как узнать количество цифр в числе?
СтрДлина(Формат(Цел(Число), "ЧГ=0")). Для 12345 вернёт 5. Знак и дробную часть предварительно уберите через Цел() и модуль, иначе они попадут в подсчёт.