Как вывести дробное число прописью в 1С с нестандартными окончаниями (например, "стотысячных")?

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

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

Изначально функция ЧислоПрописью разрабатывалась с учетом наиболее распространенных сценариев, таких как вывод денежных сумм (рубли и копейки) или количества штук. Она прекрасно справляется с целыми числами и их дробными частями, соответствующими стандартным единицам измерения. Однако, когда мы пытаемся применить ее для числа 0.16358, ожидая получить "Ноль целых шестнадцать тысяч триста пятьдесят восемь стотысячных", мы обнаруживаем, что напрямую стандартным вызовом такого результата добиться не удается.

Ограничения функции ЧислоПрописью для произвольных дробных частей

Давайте выясним основную причину, по которой стандартный вызов ЧислоПрописью(0.16358) не даст желаемого результата. Эта функция предназначена для чисел с реальными единицами измерения, которые жестко заданы в ее параметрах или внутренне определены. Она не умеет автоматически определять "стотысячные" как единицу измерения на основе количества знаков после запятой в числе. Это означает, что нам потребуется дополнительная логика для "обучения" функции или для самостоятельного формирования части строки, относящейся к дробной части.

Метод 1: Разделение числа на целую и дробную части с ручной доработкой

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

  1. Выделение целой и дробной части:

Мы начинаем с того, что отделяем целую часть от дробной. Целая часть числа 0.16358 будет равна 0. Дробная часть — 0.16358.


ИскомоеЧисло = 0.16358;
ЦелаяЧасть = Цел(ИскомоеЧисло); // Получим 0
ДробнаяЧасть = ИскомоеЧисло - ЦелаяЧасть; // Получим 0.16358

Целую часть мы можем перевести прописью с помощью стандартной функции ЧислоПрописью. В нашем случае, для 0, это будет "Ноль". К этому мы должны будем добавить слово "целых".


СтрокаЦелаяЧасть = ЧислоПрописью(ЦелаяЧасть, "ДП=Истина", "целая, целой, целых, ж");
// Если ЦелаяЧасть = 0, получим "Ноль целых"

Это самый сложный этап. Нам необходимо взять дробную часть 0.16358, преобразовать ее в целое число (умножив на соответствующую степень 10) и определить правильное окончание ("десятых", "сотых", "тысячных", "десятитысячных", "стотысячных").

Определение количества знаков после запятой:

Чтобы понять, какое окончание нам нужно, мы должны определить количество знаков после запятой в исходной дробной части. Для этого мы можем преобразовать дробную часть в строку и подсчитать ее длину после десятичного разделителя. Если исходное число было 0.16358, то после выделения дробной части 0.16358 и преобразования ее в строку, мы увидим 5 знаков после запятой (16358). Это соответствует "стотысячным".


ЧислоСимволовПослеЗапятой = СтрДлина(Сред(Строка(ИскомоеЧисло - Цел(ИскомоеЧисло)), 3));
// Для 0.16358, Строка(0.16358 - 0) даст "0.16358". Сред("0.16358", 3) даст "16358". СтрДлина("16358") даст 5.

Формирование окончания:

На основе количества знаков после запятой мы можем сформировать правильное окончание. Создадим небольшой алгоритм для определения названия разряда:


Если ЧислоСимволовПослеЗапятой = 1 Тогда
    НаименованиеРазряда = "десятая, десятых, десятых, ж";
    ДелительДляДробнойЧасти = 10;
ИначеЕсли ЧислоСимволовПослеЗапятой = 2 Тогда
    НаименованиеРазряда = "сотая, сотых, сотых, ж";
    ДелительДляДробнойЧасти = 100;
ИначеЕсли ЧислоСимволовПослеЗапятой = 3 Тогда
    НаименованиеРазряда = "тысячная, тысячных, тысячных, ж";
    ДелительДляДробнойЧасти = 1000;
ИначеЕсли ЧислоСимволовПослеЗапятой = 4 Тогда
    НаименованиеРазряда = "десятитысячная, десятитысячных, десятитысячных, ж";
    ДелительДляДробнойЧасти = 10000;
ИначеЕсли ЧислоСимволовПослеЗапятой = 5 Тогда
    НаименованиеРазряда = "стотысячная, стотысячных, стотысячных, ж";
    ДелительДляДробнойЧасти = 100000;
Иначе
    // Обработка других случаев или ошибка
    НаименованиеРазряда = "";
    ДелительДляДробнойЧасти = 1; 
КонецЕсли;

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


ДробнаяЧастьКакЦелое = Окр(ДробнаяЧасть * ДелительДляДробнойЧасти, 0); // Получим 16358 для 0.16358
СтрокаДробнаяЧасть = ЧислоПрописью(ДробнаяЧастьКакЦелое, "ДП=Истина", НаименованиеРазряда);
// Это будет выглядеть как "шестнадцать тысяч триста пятьдесят восемь стотысячных"

Нам остается только объединить полученные строки для целой и дробной части. Важно учесть случай, когда целая часть равна нулю. Мы можем добавить "Ноль целых" в начале, если ИскомоеЧисло меньше 1.


Результат = "";
Если ЦелаяЧасть = 0 Тогда
    Результат = "Ноль целых";
Иначе
    Результат = ЧислоПрописью(ЦелаяЧасть, "ДП=Истина", "целая, целой, целых, ж");
КонецЕсли;
    
Если Не ПустаяСтрока(СтрокаДробнаяЧасть) Тогда
    Результат = Результат + " " + СтрокаДробнаяЧасть;
КонецЕсли;
    
Сообщить(Результат); // Ноль целых шестнадцать тысяч триста пятьдесят восемь стотысячных

Грамматические нюансы ("рюшечки и бантики"):

Согласование окончаний в русском языке требует внимания. Например, "одна стотысячная", но "две стотысячных". Стандартная функция ЧислоПрописью уже учитывает эти правила, если мы правильно передаем ей параметры для склонения. Наши НаименованиеРазряда ("десятая, десятых, десятых, ж") как раз и позволяют ей это делать. Если мы правильно определили грамматический род (в нашем случае "ж" – женский) и формы для единственного и множественного числа, функция позаботится об остальном.

Метод 2: Динамическое формирование параметра "ДП" для ЧислоПрописью

Сообщение 7 в обсуждении демонстрирует, что ЧислоПрописью может принимать более сложный параметр для детализации дробных частей. Рассмотрим этот подход подробнее.

Функция ЧислоПрописью имеет параметр, который позволяет нам явно указать, как должны склоняться и называться различные части числа. В частности, для денежных сумм это выглядит как "рубль, рубля, рублей, м, копейка, копейки, копеек, ж, 2". Если мы хотим использовать похожий механизм для наших произвольных дробных частей, мы можем формировать эту строку динамически.

  1. Пример для тысячных:

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


Сообщить(ЧислоПрописью(5.163, "ДП=Истина", "целая, целой, целых, ж, тысячная, тысячных, тысячных, ж, 3"));

Разберем этот параметр: "целая, целой, целых, ж, тысячная, тысячных, тысячных, ж, 3".

Идея, предложенная в сообщении 8, заключается в том, чтобы динамически формировать эту строку, опираясь на количество знаков после запятой в исходном числе. Мы уже знаем, как определить ЧислоСимволовПослеЗапятой.

На основе этого количества мы можем выбрать соответствующую строку для ВтораяЧасть:


ИскомоеЧисло = 0.16358;
    
// Определяем количество знаков после запятой
СтроковоеПредставлениеЧисла = Строка(ИскомоеЧисло);
ПозицияЗапятой = Найти(СтроковоеПредставлениеЧисла, ","); // Или "." в зависимости от локали
ЧислоСимволовПослеЗапятой = 0;
Если ПозицияЗапятой > 0 Тогда
    ЧислоСимволовПослеЗапятой = СтрДлина(СтроковоеПредставлениеЧисла) - ПозицияЗапятой;
КонецЕсли;
    
ВтораяЧасть = "";
Если ЧислоСимволовПослеЗапятой = 1 Тогда
    ВтораяЧасть = "десятая, десятых, десятых, ж, 1";
ИначеЕсли ЧислоСимволовПослеЗапятой = 2 Тогда
    ВтораяЧасть = "сотая, сотых, сотых, ж, 2";
ИначеЕсли ЧислоСимволовПослеЗапятой = 3 Тогда
    ВтораяЧасть = "тысячная, тысячных, тысячных, ж, 3";
ИначеЕсли ЧислоСимволовПослеЗапятой = 4 Тогда
    ВтораяЧасть = "десятитысячная, десятитысячных, десятитысячных, ж, 4";
ИначеЕсли ЧислоСимволовПослеЗапятой = 5 Тогда
    ВтораяЧасть = "стотысячная, стотысячных, стотысячных, ж, 5";
// ... можно добавить другие варианты
Иначе
    Сообщить("Для данного числа знаков после запятой не определено соответствующее наименование дробной части.");
    Возврат;
КонецЕсли;
    
Если Не ПустаяСтрока(ВтораяЧасть) Тогда
    // Для целой части используем нейтральное "целая, целой, целых, ж" или "рубль, рубля, рублей, м" если это деньги
    // Ноль целых будет обработан, если число меньше 1
    Сообщить(ЧислоПрописью(ИскомоеЧисло, "ДП=Истина", "целая, целой, целых, ж, " + ВтораяЧасть));
КонецЕсли;

Важный момент: Если число равно 0.16358, и мы используем этот подход, ЧислоПрописью примет 0 как целую часть и автоматически сформирует "Ноль целых". Для дробной части она возьмет число 16358 и, используя параметры для "стотысячных", выведет "шестнадцать тысяч триста пятьдесят восемь стотысячных". Объединение произойдет внутри самой функции.

Как справедливо заметили в обсуждении, этот подход хорош, если количество знаков после запятой фиксировано или находится в заранее определенном диапазоне. Если у нас могут появиться 6, 7 или больше знаков после запятой, нам придется расширять наш условный оператор Если...ИначеЕсли для каждого нового случая. Это делает решение не совсем универсальным для произвольной точности, но вполне пригодным для случаев с ограниченным числом вариантов дробности (например, до 5-6 знаков).

Итоги и рекомендации

Мы рассмотрели два основных подхода к решению задачи вывода дробных чисел прописью с нестандартными окончаниями в 1С:

  1. Разделение числа и ручная сборка: Этот метод дает нам полный контроль над формированием каждой части строки. Мы можем индивидуально обрабатывать целую и дробную части, определять их прописью и затем самостоятельно склеивать результат, добавляя необходимые связующие слова. Этот подход более гибок для сложных случаев, но требует большего объема кода для реализации.
  2. Динамическое формирование параметров для ЧислоПрописью: Этот метод использует встроенные возможности функции ЧислоПрописью для обработки дробной части. Он более компактен, но требует наличия заранее подготовленных строк-параметров для каждого возможного количества знаков после запятой. Он хорошо подходит для случаев, когда диапазон точности дробной части известен и ограничен.

Какой метод выбрать, зависит от специфики вашей задачи:

В любом случае, ключ к успеху лежит в понимании того, что стандартная функция ЧислоПрописью требует явного указания, как работать с дробной частью, а для этого нам необходимо предоставить ей соответствующую информацию, либо подготовить текстовое представление дробной части самостоятельно.

← На главную