AXForum  
Вернуться   AXForum > Блоги > Gustav'ово бложище, или Записки DAX-дилетанта-III
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

Стараюсь писать про Аксапту, хотя частенько тянет в Офис
Рейтинг: 5.00. Голосов: 2.

Сумма прописью (RU): Axapta, VBA и Excel (в одной ячейке!)

Запись от Gustav размещена 13.03.2012 в 15:30

Это сообщение готовилось к публикации почти два года тому назад. Тогда мне потребовалась сумма прописью в своей разработке. Прошерстив форум, нашёл ссылки на класс RNumDateInWordConverter, но что-то с первого раза с этим классом не получилось. Потом, правда, срослось, но "осадок остался" и появилось горячее желание прикоснуться к теме лично, тем более, что в голове сложился своеобразный алгоритм решения (как мне кажется... или это только мне кажется его своеобразность? ). Этим алгоритмом мне тогда и хотелось поделиться, но текучка отложила этот радостный момент на неопределенный срок.

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

С деталями алгоритма можно ознакомиться по приведенным ниже текстам метода sumInWords_RU (для Аксапты) и одноименной же функции (для VBA).
X++:
// KKu, 23.04.2010 --> РУССКАЯ СУММА ПРОПИСЬЮ

//  _sourceReal - вещественное число для прописи (минус и дробная часть игнорируются при обработке)
//  _unit1,_unit2,_unit5 - формы считаемого существительного соответственно для 1 единицы, 2 ед-ц и 5 ед-ц
//  _gender - код рода считаемого существительного = 1-мужской, 2-женский, 3-средний
//  _capital - в возвращаемой строке делать большими буквы:
//      0-всё маленькими, 1-только самую первую букву всей строки,2-первая буква каждой триады

static str sumInWords_RU( real  _sourceReal,
                          str   _unit1   = 'рубль',  // (один) рубль
                          str   _unit2   = 'рубля',  // (два ) рубля
                          str   _unit5   = 'рублей', // (пять) рублей
                          int   _gender  = 1,        // 1 - мужской (рубль)
                          int   _capital = 1 )       // 1 - только первая всей строки
{
    str         strSource = strFmt('00%1', num2str( trunc((abs(_sourceReal))),1,0,1,0 ));
    int         cntTriad  = trunc(strLen(strSource)/3);
    str         urrTriad, morePwr12, fRet;
    int         i;

    str triadWords(str triad, str unit1, str unit2, str unit5, int gender)
    {
        str ret  = conPeek(['','сто ','двести ','триста ','четыреста ',
                    'пятьсот ','шестьсот ','семьсот ','восемьсот ','девятьсот '],
                    str2int(subStr(triad,1,1))+1 );
        str currUnit = unit5;
        ;
        if (strSource=='000')
        {
            ret = 'ноль ';
        }
        else if (subStr(triad,2,1)=='1')
        {
            ret += conPeek(['десять','одиннадцать','двенадцать','тринадцать','четырнадцать',
                    'пятнадцать','шестнадцать','семнадцать','восемнадцать','девятнадцать'],
                    str2int(subStr(triad,2,2))-9 ) + ' ';
        }
        else
        {
            ret += conPeek(['','','двадцать ','тридцать ','сорок ',
                    'пятьдесят ','шестьдесят ','семьдесят ','восемьдесят ','девяносто '],
                    str2int(subStr(triad,2,1))+1 );

            ret += conPeek(['',conPeek(['один ','одна ','одно '],gender),
                    conPeek(['два ' ,'две ' ,'два ' ],gender),
                    'три ','четыре ','пять ','шесть ','семь ','восемь ','девять '],
                    str2int(subStr(triad,3,1))+1 );

            currUnit = conPeek([unit5, unit1, unit2,unit2,unit2, unit5,unit5,unit5,unit5,unit5],
                        str2int(subStr(triad,3,1))+1 );
        }
        return ret ? strFmt('%1%2 ', str2Capital(ret), currUnit) : (cntTriad-i+1)==1 ? currUnit : '';
    }
    ;

    strSource = subStr(strSource, strLen(strSource)-cntTriad*3+1, cntTriad*3);
    for (i=1; i<=cntTriad; i++)
    {
        urrTriad = subStr(strSource, (i-1)*3+1, 3);
        switch (cntTriad-i+1)
        {
            case 1: fRet += triadWords(urrTriad,_unit1    ,_unit2     ,_unit5,_gender); break; // 10^0
            case 2: fRet += triadWords(urrTriad,'тысяча'  ,'тысячи'   ,'тысяч'     ,2); break; // 10^3
            case 3: fRet += triadWords(urrTriad,'миллион' ,'миллиона' ,'миллионов' ,1); break; // 10^6
            case 4: fRet += triadWords(urrTriad,'миллиард','миллиарда','миллиардов',1); break; // 10^9
            case 5: fRet += triadWords(urrTriad,'триллион','триллиона','триллионов',1); break; // 10^12
            default:
                    morePwr12 = strFmt('10^%1',(cntTriad-i)*3); // 10^15 и т.д.
                    fRet += triadWords(urrTriad, morePwr12, morePwr12 , morePwr12  ,1);
        }
    }
    return strRTrim(conPeek([strLwr(fRet), str2Capital(strLwr(fRet)), fRet], _capital+1));
}
VBA:
X++:
''//РУССКАЯ СУММА ПРОПИСЬЮ - функция sumInWords_RU
Option Explicit

Dim strSource   As String
Dim cntTriad    As Integer
Dim i           As Integer

Private Function triadWords(ByVal triad As String, _
                            ByVal unit1 As String, _
                            ByVal unit2 As String, _
                            ByVal unit5 As String, _
                            ByVal gender As Integer) As String
                            
    Dim ret         As String
    Dim currUnit    As String
    
    ret = Choose(CInt(Left(triad, 1)) + 1, "", "сто ", "двести ", "триста ", "четыреста ", _
                "пятьсот ", "шестьсот ", "семьсот ", "восемьсот ", "девятьсот ")
    currUnit = unit5
    
    If strSource = "000" Then
        ret = "ноль "
        
    ElseIf Mid(triad, 2, 1) = "1" Then
        ret = ret & Choose(CInt(Right(triad, 2)) - 9, "десять", "одиннадцать", _
                    "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", _
                    "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать") & " "
    Else
        ret = ret & Choose(CInt(Mid(triad, 2, 1)) + 1, "", "", _
                    "двадцать ", "тридцать ", "сорок ", "пятьдесят ", _
                    "шестьдесят ", "семьдесят ", "восемьдесят ", "девяносто ")
        ret = ret & Choose(CInt(Right(triad, 1)) + 1, "", _
                    Choose(gender, "один", "одна", "одно") & " ", _
                    Choose(gender, "два", "две", "два") & " ", _
                    "три ", "четыре ", "пять ", "шесть ", "семь ", "восемь ", "девять ")
        currUnit = Choose(CInt(Right(triad, 1)) + 1, _
                    unit5, unit1, unit2, unit2, unit2, _
                    unit5, unit5, unit5, unit5, unit5)
    End If
    
    triadWords = IIf(ret <> "", UCase(Left(ret, 1)) & Mid(ret, 2) & currUnit & " ", _
                                IIf((cntTriad - i + 1) = 1, currUnit, ""))
End Function

''//РУССКАЯ СУММА ПРОПИСЬЮ
''//  sourceReal - вещественное число для прописи (минус и дробная часть игнорируются при обработке)
''//  unit1, unit2, unit5 - формы считаемого существительного соответственно для 1 единицы, 2 ед-ц и 5 ед-ц
''//  gender - код рода считаемого существительного = 1-мужской, 2-женский, 3-средний
''//  capital - в возвращаемой строке делать большими буквы:
''//     0-всё маленькими, 1-только самую первую букву всей строки,2-первая буква каждой триады
Public Function sumInWords_RU(ByVal sourceReal As Double, _
                              Optional ByVal unit1 As String = "рубль", _
                              Optional ByVal unit2 As String = "рубля", _
                              Optional ByVal unit5 As String = "рублей", _
                              Optional ByVal gender As Integer = 1, _
                              Optional ByVal capital As Integer = 1) As String

    Dim urTrd      As String
    Dim morePwr12   As String
    Dim fRet        As String
   
    strSource = "00" & Format(Int(Abs(sourceReal)), "0")
    cntTriad = Int(Len(strSource) / 3)
    strSource = Right(strSource, cntTriad * 3)
    
    For i = 1 To cntTriad
        urTrd = Mid(strSource, (i - 1) * 3 + 1, 3)
        Select Case cntTriad - i + 1
            Case 1: fRet = fRet & triadWords(urTrd, unit1, unit2, unit5, gender)
            Case 2: fRet = fRet & triadWords(urTrd, "тысяча", "тысячи", "тысяч", 2)
            Case 3: fRet = fRet & triadWords(urTrd, "миллион", "миллиона", "миллионов", 1)
            Case 4: fRet = fRet & triadWords(urTrd, "миллиард", "миллиарда", "миллиардов", 1)
            Case 5: fRet = fRet & triadWords(urTrd, "триллион", "триллиона", "триллионов", 1)
            Case Else
                morePwr12 = "10^" & CStr(cntTriad - i) * 3
                fRet = fRet & triadWords(urTrd, morePwr12, morePwr12, morePwr12, 1)
        End Select
    Next i
    
    sumInWords_RU = RTrim(Choose(capital + 1, LCase(fRet), Left(fRet, 1) & LCase(Mid(fRet, 2)), fRet))
End Function
Но что же заставило меня наконец перевести это сообщение из статуса "черновик" в открытый доступ? А вот что - на основе ранее разработанных вышеприведенных функций сочинилась формула для Excel, помещающаяся в одной ячейке! Т.е. в ячейку А1 вводим число, в ячейку B1 - формулу и в ней же читаем сумму прописью. Никаких макросов, весь текст собирается в одной ячейке с использованием стандартных функций рабочего листа (у кого-нибудь есть образец заявки в книгу рекордов Гиннесса? )

По терминологии маэстро Дж.Уокенбаха эта формула - мегаформула (не в смысле, что такая крутая, а потому что без промежуточных результатов). С количеством символов около 6 тысяч - поэтому может использоваться только в версии Excel, начиная с 2007, когда допустимая длина формулы увеличилась с 1024 до 8192 символов. Для более ранних версий, однако, возможен "расчет" суммы прописью с задействованием нескольких соседних ячеек (и существенным сокращением общего кол-ва формульных символов за счет использования формул массива). Но об этом позже, а сейчас - вот эта базовая формулища:

МЕГАФОРМУЛА ДЛЯ ОДНОЙ ЯЧЕЙКИ EXCEL:
X++:
=(((
(
((("0";15)&((ABS(A1);2));15);3)
+0=0;""
;
((
((("0";15)&((ABS(A1);2));15);3)
)+1
;"";"стоs";"двестиs";"тристаs";"четырестаs";
"пятьсотs";"шестьсотs";"семьсотs";"восемьсотs";"девятьсотs")
&
((
((("0";15)&((ABS(A1);2));15);3)
;2;1)+0=1;
((
((("0";15)&((ABS(A1);2));15);3)
;2)-9
;"десятьs";"одиннадцатьs";"двенадцатьs";"тринадцатьs";"четырнадцатьs";
"пятнадцатьs";"шестнадцатьs";"семнадцатьs";"восемнадцатьs";"девятнадцатьs")
&"триллионов "
;
((
((("0";15)&((ABS(A1);2));15);3)
;2;1)+1
;"";"";"двадцатьs";"тридцатьs";"сорокs";
"пятьдесятs";"шестьдесятs";"семьдесятs";"восемьдесятs";"девяностоs")
&
((
((("0";15)&((ABS(A1);2));15);3)
)+1
;"триллионов ";"одинsтриллион ";"дваsтриллиона ";"триsтриллиона ";"четыреsтриллиона ";
"пятьsтриллионов ";"шестьsтриллионов ";"семьsтриллионов ";"восемьsтриллионов ";"девятьsтриллионов ")
))
&
(
((("0";15)&((ABS(A1);2));12);3)
+0=0;""
;
((
((("0";15)&((ABS(A1);2));12);3)
)+1
;"";"стоs";"двестиs";"тристаs";"четырестаs";
"пятьсотs";"шестьсотs";"семьсотs";"восемьсотs";"девятьсотs")
&
((
((("0";15)&((ABS(A1);2));12);3)
;2;1)+0=1;
((
((("0";15)&((ABS(A1);2));12);3)
;2)-9
;"десятьs";"одиннадцатьs";"двенадцатьs";"тринадцатьs";"четырнадцатьs";
"пятнадцатьs";"шестнадцатьs";"семнадцатьs";"восемнадцатьs";"девятнадцатьs")
&"миллиардов "
;
((
((("0";15)&((ABS(A1);2));12);3)
;2;1)+1
;"";"";"двадцатьs";"тридцатьs";"сорокs";
"пятьдесятs";"шестьдесятs";"семьдесятs";"восемьдесятs";"девяностоs")
&
((
((("0";15)&((ABS(A1);2));12);3)
)+1
;"миллиардов ";"одинsмиллиард ";"дваsмиллиарда ";"триsмиллиарда ";"четыреsмиллиарда ";
"пятьsмиллиардов ";"шестьsмиллиардов ";"семьsмиллиардов ";"восемьsмиллиардов ";"девятьsмиллиардов ")
))
&
(
((("0";15)&((ABS(A1);2));9);3)
+0=0;""
;
((
((("0";15)&((ABS(A1);2));9);3)
)+1
;"";"стоs";"двестиs";"тристаs";"четырестаs";
"пятьсотs";"шестьсотs";"семьсотs";"восемьсотs";"девятьсотs")
&
((
((("0";15)&((ABS(A1);2));9);3)
;2;1)+0=1;
((
((("0";15)&((ABS(A1);2));9);3)
;2)-9
;"десятьs";"одиннадцатьs";"двенадцатьs";"тринадцатьs";"четырнадцатьs";
"пятнадцатьs";"шестнадцатьs";"семнадцатьs";"восемнадцатьs";"девятнадцатьs")
&"миллионов "
;
((
((("0";15)&((ABS(A1);2));9);3)
;2;1)+1
;"";"";"двадцатьs";"тридцатьs";"сорокs";
"пятьдесятs";"шестьдесятs";"семьдесятs";"восемьдесятs";"девяностоs")
&
((
((("0";15)&((ABS(A1);2));9);3)
)+1
;"миллионов ";"одинsмиллион ";"дваsмиллиона ";"триsмиллиона ";"четыреsмиллиона ";
"пятьsмиллионов ";"шестьsмиллионов ";"семьsмиллионов ";"восемьsмиллионов ";"девятьsмиллионов ")
))
&
(
((("0";15)&((ABS(A1);2));6);3)
+0=0;""
;
((
((("0";15)&((ABS(A1);2));6);3)
)+1
;"";"стоs";"двестиs";"тристаs";"четырестаs";
"пятьсотs";"шестьсотs";"семьсотs";"восемьсотs";"девятьсотs")
&
((
((("0";15)&((ABS(A1);2));6);3)
;2;1)+0=1;
((
((("0";15)&((ABS(A1);2));6);3)
;2)-9
;"десятьs";"одиннадцатьs";"двенадцатьs";"тринадцатьs";"четырнадцатьs";
"пятнадцатьs";"шестнадцатьs";"семнадцатьs";"восемнадцатьs";"девятнадцатьs")
&"тысяч "
;
((
((("0";15)&((ABS(A1);2));6);3)
;2;1)+1
;"";"";"двадцатьs";"тридцатьs";"сорокs";
"пятьдесятs";"шестьдесятs";"семьдесятs";"восемьдесятs";"девяностоs")
&
((
((("0";15)&((ABS(A1);2));6);3)
)+1
;"тысяч ";"однаsтысяча ";"двеsтысячи ";"триsтысячи ";"четыреsтысячи ";
"пятьsтысяч ";"шестьsтысяч ";"семьsтысяч ";"восемьsтысяч ";"девятьsтысяч ")
))
&
(
(("0";15)&((ABS(A1);2));3)
+0=0;(((ABS(A1);2))=0;"нольsрублей";"sрублей")
;
((
(("0";15)&((ABS(A1);2));3)
)+1
;"";"стоs";"двестиs";"тристаs";"четырестаs";
"пятьсотs";"шестьсотs";"семьсотs";"восемьсотs";"девятьсотs")
&
((
(("0";15)&((ABS(A1);2));3)
;2;1)+0=1;
((
(("0";15)&((ABS(A1);2));3)
;2)-9
;"десятьs";"одиннадцатьs";"двенадцатьs";"тринадцатьs";"четырнадцатьs";
"пятнадцатьs";"шестнадцатьs";"семнадцатьs";"восемнадцатьs";"девятнадцатьs")
&"рублей"
;
((
(("0";15)&((ABS(A1);2));3)
;2;1)+1
;"";"";"двадцатьs";"тридцатьs";"сорокs";
"пятьдесятs";"шестьдесятs";"семьдесятs";"восемьдесятs";"девяностоs")
&
((
(("0";15)&((ABS(A1);2));3)
)+1
;"";(1;"одинs";"однаs";"одноs");
(1;"дваs";"двеs";"дваs");"триs";"четыреs";
"пятьs";"шестьs";"семьs";"восемьs";"девятьs")
&
(((
(("0";15)&((ABS(A1);2));3)
)+1;3;1;2;2;2;3;3;3;3;3);
"рубль";"рубля";"рублей")
))
);"s";" ");"S";"")
&
" " & (
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;2)&" "
&
(((
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;3)+0=0;((
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;3);2;1)+0=1);
"копеек";
((((
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;3))+1;3;1;2;2;2;3;3;3;3;3);
"копейка";"копейки";"копеек")
)
В отличие от вышеприведенных метода и функции, "проговаривающих" только целые числа, эта формула содержит еще и блок копеек, т.е. дробной части. Формула также приводится в прилагаемом файле, чтобы владельцы копий Excel, отличных от русской, либо русской, но с иными разделителями, тоже могли ею воспользоваться.

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

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

Для облегчения ориентирования в тексте формулы - блок триллионов ограничен фрагментами (фрагменты входят в состав блока):
X++:
(
((("0";15)&((ABS(A1);2));15);3)
+0=0;""
;
.......................................................................
.......................................................................
.......................................................................
;"триллионов ";"одинsтриллион ";"дваsтриллиона ";"триsтриллиона ";"четыреsтриллиона ";
"пятьsтриллионов ";"шестьsтриллионов ";"семьsтриллионов ";"восемьsтриллионов ";"девятьsтриллионов ")
))
&
Блоки остальных разрядностей можно найти по аналогии. Дополнительным средством идентификации блока триллионов может быть второе число 15 в характерной подстроке ЛЕВСИМВ(ПРАВСИМВ(ПОВТОР("0";15)&ЦЕЛОЕ(ОКРУГЛ(ABS(A1);2));15);3). Для миллиардов это число будет 12, для миллионов - 9, для тысяч - 6 (думаю, комментарии излишни).

Конечно же, с вычислительной точки зрения мегаформула (назовем ее "алгоритмом в одной ячейке") вопиюще неоптимальна. Невооруженным глазом видны многократно повторяющиеся одинаковые фрагменты. И всё в угоду тому, чтобы содержать ссылки на одну единственную ячейку A1 - и тем самым производить впечатление экспоната кунсткамеры. Но, согласитесь, прикольно! А современные компы потянут и не такие вычисления

Если же количество задействованных для расчета суммы прописью ячеек для нас не имеет значения (в разумных пределах), то можно использовать "алгоритм в нескольких ячейках". Общее количество символов во всех используемых при этом формулах будет существенно меньше и в самой "насыщенной" не превысит значения 1024, что позволит применить "алгоритм в нескольких ячейках" также и в более ранних версиях Excel (до 2007).

Ниже введем на рабочем листе Excel несколько формул, являющихся составными частями алгоритма в нескольких ячейках. Общее количество задействованных ячеек - 12. Можно уменьшить до 10, если объединить в одной ячейке "рубли", "копейки" и "сцепить" (если только не актуально ограничение на длину формулы в 1024 символа). И дальше - уменьшение на 2 ячейки при каждом отказе от использования старших разрядов (триллионов, миллиардов и т.д.). Для сумм меньше миллиона можно будет уложиться в 4 ячейки.

Итак, формула для ячеек B1:F1 - в них будут отображаться триады цифрами (диапазон содержит 5 ячеек):
X++:
=((("0";15)&((ABS(A1);2));{15;12;9;6;3});3)
Эта формула массива должна быть введена при помощи следующих шагов: копируем ее текст отсюда; в Excel выделяем диапазон B1:F1; жмем F2 для перехода в режим редактирования; в строке редактирования делаем вставку из буфера; завершаем ввод нажатием комбинации Shift+Ctrl+Enter.

Для ячеек G1:J1 - триады словами (4 ячейки!):
X++:
=((
(B1:E1+0=0
;
""
;
((B1:E1)+1;
"";"стоs";"двестиs";"тристаs";"четырестаs";
"пятьсотs";"шестьсотs";"семьсотs";"восемьсотs";"девятьсотs")
&
((B1:E1;2;1)+0=1
;
((B1:E1;2)-9;
"десятьs";"одиннадцатьs";"двенадцатьs";"тринадцатьs";"четырнадцатьs";
"пятнадцатьs";"шестнадцатьs";"семнадцатьs";"восемнадцатьs";"девятнадцатьs")
&{"триллионов ";"миллиардов ";"миллионов ";"тысяч "}
;
((B1:E1;2;1)+1;
"";"";"двадцатьs";"тридцатьs";"сорокs";
"пятьдесятs";"шестьдесятs";"семьдесятs";"восемьдесятs";"девяностоs")
&
((B1:E1)+1;
"";({1;1;1;1};"одинs";"однаs";"одноs");
({1;1;1;2};"дваs";"двеs";"дваs");"триs";"четыреs";
"пятьs";"шестьs";"семьs";"восемьs";"девятьs")
&
{"триллион";"миллиард";"миллион";"тысяч"}&
(((B1:E1)+1;3;1;2;2;2;3;3;3;3;3);
{" ";" ";" ";"а "};{"а ";"а ";"а ";"и "};{"ов ";"ов ";"ов ";" "})
))
);"s";" ")
Эта тоже формула массива, которая вводится тем же способом, что и предыдущая. Следует обратить внимание, что эта формула будет занимать 4 ячейки, а не 5 как предыдущая. 5-ю ячейку (рублей) мы введем отдельно (почему - будет понятно далее из файла, при рассмотрении параметрического варианта алгоритма).

Для ячейки K1 - рубли (обычная формула - ввод завершается простым нажатием Enter):
X++:
=(((
(F1+0=0
;
((ABS(A1))=0;"нольsрублей";"sрублей")
;
((F1)+1;
"";"стоs";"двестиs";"тристаs";"четырестаs";
"пятьсотs";"шестьсотs";"семьсотs";"восемьсотs";"девятьсотs")
&
((F1;2;1)+0=1
;
((F1;2)-9;
"десятьs";"одиннадцатьs";"двенадцатьs";"тринадцатьs";"четырнадцатьs";
"пятнадцатьs";"шестнадцатьs";"семнадцатьs";"восемнадцатьs";"девятнадцатьs")
&"рублей"
;
((F1;2;1)+1;
"";"";"двадцатьs";"тридцатьs";"сорокs";
"пятьдесятs";"шестьдесятs";"семьдесятs";"восемьдесятs";"девяностоs")
&
((F1)+1;
"";(1;"одинs";"однаs";"одноs");
(1;"дваs";"двеs";"дваs");"триs";"четыреs";
"пятьs";"шестьs";"семьs";"восемьs";"девятьs")
&
(((F1)+1;3;1;2;2;2;3;3;3;3;3);
"рубль";"рубля";"рублей")
))
);"s";" ");"S";"")

Для ячейки L1 - копейки (обычная формула - ввод завершается простым нажатием Enter):
X++:
=" " & (
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;2)&" "
&
(((
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;3)+0=0;((
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;3);2;1)+0=1);
"копеек";
((((
(("0";((2/3)+1)*3)&(((ABS(A1);2)-((ABS(A1);2)))*10^2;0);((2/3)+1)*3)
;3))+1;3;1;2;2;2;3;3;3;3;3);
"копейка";"копейки";"копеек")
)
Возможно, вы заметили, что в этой формуле (и в других) присутствуют фрагменты, которые могли бы быть вычислены заранее и введены в формулу как константы, например: (ЦЕЛОЕ(2/3)+1)*3) или 10^2. Это сделано сознательно - в таком виде легче конструировать универсальные параметрические формулы на случаи любых единиц измерения, а не только рублей и копеек. В параметрическом варианте (см. в файле) число 2 в этих примерах, которое по сути представляет собой кол-во знаков дробной части, заменено ссылкой на ячейку, в которой хранится данная величина.

Наконец, в ячейке M1 получаем окончательную сумму прописью:
X++:
=(G1;H1;I1;J1;K1;L1)

// удивительно упорство Microsoft по непредоставлению до сих пор возможности записи этой формулы в виде =СЦЕПИТЬ(G1:L1)
Простую формулу в ячейке M1 можно усложнить дополнительной обработкой по желанию, например, оставив заглавной только самую первую букву фразы:
X++:
=((G1;H1;I1;J1;K1;L1))&(((G1;H1;I1;J1;K1;L1);2;1000))

// здесь 1000 - произвольное, заведомо большее длины строки число
В прилагаемом файле на основе приведенных формул алгоритма в нескольких ячейках демонстрируется также его параметрический вариант - на случай любых единиц измерения. Настройка на любые единицы выполняется путем указания необходимых параметров (род единиц, формы считаемых существительных, кол-во знаков дробной части) в дополнительных ячейках. С несложными деталями можно ознакомиться самостоятельно. Файл создан в Excel 2010.
Вложения
Тип файла: xlsx SumInWords_Excel2010.xlsx (18.3 Кб, 2166 просмотров)
Размещено в Без категории
Просмотров 255262 Комментарии 1
Всего комментариев 1

Комментарии

  1. Старый комментарий
    Аватар для Gustav
    К сожалению, приаттаченные к сообщениям файлы могут видеть только зарегистрированные участники форума. Если Вы - незарегистрированный гость, но хотели бы получить файл - напишите мне об этом на Gustav@axforum.info и я пришлю его. Возможно, придется подождать несколько дней (так как проверяю этот адрес не каждый день).
    Запись от Gustav размещена 23.03.2012 в 19:57 Gustav is offline
 


Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 23:14.