Стараюсь писать про Аксапту, хотя частенько тянет в Офис
Сумма прописью (RU): Axapta, VBA и Excel (в одной ячейке!)
Запись от Gustav размещена 13.03.2012 в 15:30
Это сообщение готовилось к публикации почти два года тому назад. Тогда мне потребовалась сумма прописью в своей разработке. Прошерстив форум, нашёл ссылки на класс RNumDateInWordConverter, но что-то с первого раза с этим классом не получилось. Потом, правда, срослось, но "осадок остался" и появилось горячее желание прикоснуться к теме лично, тем более, что в голове сложился своеобразный алгоритм решения (как мне кажется... или это только мне кажется его своеобразность? ). Этим алгоритмом мне тогда и хотелось поделиться, но текучка отложила этот радостный момент на неопределенный срок.
Предлагаемый алгоритм основывается на переводе исходного числа (его целой части) в последовательность триад и в обработке каждой триады как числа от 0 до 999. При этом к соответствующей разрядности типа "тысяч", "миллионов", "миллиардов" относимся так же, как к любому считаемому существительному, например, к "рублям" или иным единицам (метрам, штукам и т.п.). Это позволяет вынести алгоритм обработки триады в отдельную, достаточно компактную функцию, снаружи которой процесс сводится к нескольким ее вызовам с соответствующей считаемой единицей в качестве параметра.
С деталями алгоритма можно ознакомиться по приведенным ниже текстам метода sumInWords_RU (для Аксапты) и одноименной же функции (для VBA).
VBA:
Но что же заставило меня наконец перевести это сообщение из статуса "черновик" в открытый доступ? А вот что - на основе ранее разработанных вышеприведенных функций сочинилась формула для Excel, помещающаяся в одной ячейке! Т.е. в ячейку А1 вводим число, в ячейку B1 - формулу и в ней же читаем сумму прописью. Никаких макросов, весь текст собирается в одной ячейке с использованием стандартных функций рабочего листа (у кого-нибудь есть образец заявки в книгу рекордов Гиннесса? )
По терминологии маэстро Дж.Уокенбаха эта формула - мегаформула (не в смысле, что такая крутая, а потому что без промежуточных результатов). С количеством символов около 6 тысяч - поэтому может использоваться только в версии Excel, начиная с 2007, когда допустимая длина формулы увеличилась с 1024 до 8192 символов. Для более ранних версий, однако, возможен "расчет" суммы прописью с задействованием нескольких соседних ячеек (и существенным сокращением общего кол-ва формульных символов за счет использования формул массива). Но об этом позже, а сейчас - вот эта базовая формулища:
МЕГАФОРМУЛА ДЛЯ ОДНОЙ ЯЧЕЙКИ EXCEL:
В отличие от вышеприведенных метода и функции, "проговаривающих" только целые числа, эта формула содержит еще и блок копеек, т.е. дробной части. Формула также приводится в прилагаемом файле, чтобы владельцы копий Excel, отличных от русской, либо русской, но с иными разделителями, тоже могли ею воспользоваться.
Буковка "s" на конце числительных символизирует "пробел" ("space") и предназначена для корректной работы функции ПРОПНАЧ по переводу в верхний регистр только первой буквы каждой триады (иначе, в случае настоящего пробела, прописной стала бы первая буква в каждом слове).
Верхняя граница действия формулы - 999 триллионов (15-тизначное число). Если такие гигантские суммы не предполагается прописывать словами в повседневной хозяйственной практике, то формулу можно подрезать, удалив из нее, скажем, блоки триллионов и миллиардов, ограничив, таким образом, ее значением суммы в 999 миллионов, а то и 999 тысяч, если удалить еще и блок миллионов.
Для облегчения ориентирования в тексте формулы - блок триллионов ограничен фрагментами (фрагменты входят в состав блока):
Блоки остальных разрядностей можно найти по аналогии. Дополнительным средством идентификации блока триллионов может быть второе число 15 в характерной подстроке ЛЕВСИМВ(ПРАВСИМВ(ПОВТОР("0";15)&ЦЕЛОЕ(ОКРУГЛ(ABS(A1);2));15);3). Для миллиардов это число будет 12, для миллионов - 9, для тысяч - 6 (думаю, комментарии излишни).
Конечно же, с вычислительной точки зрения мегаформула (назовем ее "алгоритмом в одной ячейке") вопиюще неоптимальна. Невооруженным глазом видны многократно повторяющиеся одинаковые фрагменты. И всё в угоду тому, чтобы содержать ссылки на одну единственную ячейку A1 - и тем самым производить впечатление экспоната кунсткамеры. Но, согласитесь, прикольно! А современные компы потянут и не такие вычисления
Если же количество задействованных для расчета суммы прописью ячеек для нас не имеет значения (в разумных пределах), то можно использовать "алгоритм в нескольких ячейках". Общее количество символов во всех используемых при этом формулах будет существенно меньше и в самой "насыщенной" не превысит значения 1024, что позволит применить "алгоритм в нескольких ячейках" также и в более ранних версиях Excel (до 2007).
Ниже введем на рабочем листе Excel несколько формул, являющихся составными частями алгоритма в нескольких ячейках. Общее количество задействованных ячеек - 12. Можно уменьшить до 10, если объединить в одной ячейке "рубли", "копейки" и "сцепить" (если только не актуально ограничение на длину формулы в 1024 символа). И дальше - уменьшение на 2 ячейки при каждом отказе от использования старших разрядов (триллионов, миллиардов и т.д.). Для сумм меньше миллиона можно будет уложиться в 4 ячейки.
Итак, формула для ячеек B1:F1 - в них будут отображаться триады цифрами (диапазон содержит 5 ячеек):
Эта формула массива должна быть введена при помощи следующих шагов: копируем ее текст отсюда; в Excel выделяем диапазон B1:F1; жмем F2 для перехода в режим редактирования; в строке редактирования делаем вставку из буфера; завершаем ввод нажатием комбинации Shift+Ctrl+Enter.
Для ячеек G1:J1 - триады словами (4 ячейки!):
Эта тоже формула массива, которая вводится тем же способом, что и предыдущая. Следует обратить внимание, что эта формула будет занимать 4 ячейки, а не 5 как предыдущая. 5-ю ячейку (рублей) мы введем отдельно (почему - будет понятно далее из файла, при рассмотрении параметрического варианта алгоритма).
Для ячейки K1 - рубли (обычная формула - ввод завершается простым нажатием Enter):
Для ячейки L1 - копейки (обычная формула - ввод завершается простым нажатием Enter):
Возможно, вы заметили, что в этой формуле (и в других) присутствуют фрагменты, которые могли бы быть вычислены заранее и введены в формулу как константы, например: (ЦЕЛОЕ(2/3)+1)*3) или 10^2. Это сделано сознательно - в таком виде легче конструировать универсальные параметрические формулы на случаи любых единиц измерения, а не только рублей и копеек. В параметрическом варианте (см. в файле) число 2 в этих примерах, которое по сути представляет собой кол-во знаков дробной части, заменено ссылкой на ячейку, в которой хранится данная величина.
Наконец, в ячейке M1 получаем окончательную сумму прописью:
Простую формулу в ячейке M1 можно усложнить дополнительной обработкой по желанию, например, оставив заглавной только самую первую букву фразы:
В прилагаемом файле на основе приведенных формул алгоритма в нескольких ячейках демонстрируется также его параметрический вариант - на случай любых единиц измерения. Настройка на любые единицы выполняется путем указания необходимых параметров (род единиц, формы считаемых существительных, кол-во знаков дробной части) в дополнительных ячейках. С несложными деталями можно ознакомиться самостоятельно. Файл создан в Excel 2010.
Предлагаемый алгоритм основывается на переводе исходного числа (его целой части) в последовательность триад и в обработке каждой триады как числа от 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)); }
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
По терминологии маэстро Дж.Уокенбаха эта формула - мегаформула (не в смысле, что такая крутая, а потому что без промежуточных результатов). С количеством символов около 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); "копейка";"копейки";"копеек") )
Буковка "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триллионов ") )) &
Конечно же, с вычислительной точки зрения мегаформула (назовем ее "алгоритмом в одной ячейке") вопиюще неоптимальна. Невооруженным глазом видны многократно повторяющиеся одинаковые фрагменты. И всё в угоду тому, чтобы содержать ссылки на одну единственную ячейку 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)
Для ячеек 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";" ")
Для ячейки 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); "копейка";"копейки";"копеек") )
Наконец, в ячейке M1 получаем окончательную сумму прописью:
X++:
=(G1;H1;I1;J1;K1;L1)
// удивительно упорство Microsoft по непредоставлению до сих пор возможности записи этой формулы в виде =СЦЕПИТЬ(G1:L1)
X++:
=((G1;H1;I1;J1;K1;L1))&(((G1;H1;I1;J1;K1;L1);2;1000))
// здесь 1000 - произвольное, заведомо большее длины строки число
Всего комментариев 1
Комментарии
-
К сожалению, приаттаченные к сообщениям файлы могут видеть только зарегистрированные участники форума. Если Вы - незарегистрированный гость, но хотели бы получить файл - напишите мне об этом на Gustav@axforum.info и я пришлю его. Возможно, придется подождать несколько дней (так как проверяю этот адрес не каждый день).
Запись от Gustav размещена 23.03.2012 в 19:57