12 мая 2014
Кравченко Виктор

Функции СуммаПрописью, ЧислоПрописью

VB.NET Полезные функции
01

Очень часто возникает необходимость получить число или сумму, выраженную в какой-либо денежной единице прописью. Например из 1 253 458.76 руб. получить Один миллион двести пятьдесят три тысячи четыреста пятьдесят восемь рублей 76 копеек, или из 0.02485 получить ноль целых две тысячи четыреста восемьдесят пять стотысячных.

02

Вопреки традиции начну с конца — вместе с вариантами использования покажу возможности:

03 VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
'Сумма прописью в рублях Console.WriteLine(СуммаПрописьюВРублях(4582154.25)) 'четыре миллиона пятьсот восемьдесят две тысячи сто пятьдесят четыре рубля 25 копеек 'Сумма прописью в евро Console.WriteLine(СуммаПрописьюВЕвро(34654.04)) 'тридцать четыре тысячи шестьсот пятьдесят четыре евро 4 цента 'Сумма прописью в долларах Console.WriteLine(СуммаПрописьюВДолларах(39531.85)) 'тридцать девять тысяч пятьсот тридцать один доллар 85 центов 'Сумма в произвольной валюте - турецких лирах Console.WriteLine(СуммаПрописью(23645.2, "ж|лира|лиры|лир", "м|куруш|куруша|курушей")) 'двадцать три тысячи шестьсот сорок пять лир 20 курушей 'Сумма прописью в рублях, если копеек нет, то не выводим Console.WriteLine(СуммаПрописью(4582, "м|рубль|рубля|рублей", "ж|копейка|копейки|копеек", , False)) 'четыре тысячи пятьсот восемьдесят два рубля 'Сумма прописью в рублях, копейки тоже прописью Console.WriteLine(СуммаПрописью(68463.54, "м|рубль|рубля|рублей", "ж|копейка|копейки|копеек", , , False)) 'шестьдесят восемь тысяч четыреста шестьдесят три рубля пятьдесят четыре копейки 'Любые количества чего угодно Console.WriteLine(СуммаПрописью(4582, "м|ящик|ящика|ящиков", "", , False)) 'четыре тысячи пятьсот восемьдесят два ящика 'Любые количества чего угодно Console.WriteLine(ЧислоПрописью(49.45, 2) + " процента") 'сорок девять целых сорок пять сотых процента 'Число прописью с 2-мя десятичными Console.WriteLine(ЧислоПрописью(4582.85245, 2)) 'четыре тысячи пятьсот восемьдесят две целых восемьдесят пять сотых 'Число прописью без целых Console.WriteLine(ЧислоПрописью(0.85245, 5)) 'ноль целых восемьдесят пять тысяч двести сорок пять стотысячных
04

Ну а теперь сами функции СуммаПрописью и ЧислоПрописью с комментариями в коде:

05 VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#Region "СуммаПрописью" #Region "Константы числительных" 'Мужской род, женский род, средний род Dim numbers1() As String = {"ноль", "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", _ "ноль", "одна", "две", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", _ "ноль", "одно", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять"} Dim numbers10() As String = {"ноль", "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто"} Dim numbers100() As String = {"ноль", "сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот"} Dim numbers10_20() As String = {"десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"} Dim numbersDec() As String = {"десятая", "сотая", "тысячная", "десятитысячная", "стотысячная", "миллионная", "десятимиллионняа", "стомиллионняа", "миллиардняа", "десятимиллиардняа", _ "десятых", "сотых", "тысячных", "десятитысячных", "стотысячных", "миллионных", "десятимиллионных", "стомиллионных", "миллиардных", "десятимиллиардных", _ "десятых", "сотых", "тысячных", "десятитысячных", "стотысячных", "миллионных", "десятимиллионных", "стомиллионных", "миллиардных", "десятимиллиардных"} Dim periods_m() As String = {"тысяча", "миллион", "миллиард", "триллион", "квадриллион", _ "тысячи", "миллиона", "миллиарда", "триллиона", "квадриллиона", _ "тысяч", "миллионов", "миллиардов", "триллионов", "квадриллионов"} Dim periods_m_rod() As String = {"ж", "м", "м", "м", "м"} 'Роды порядков #End Region
'СуммаПрописью(1254.5, "м|рубль|рубля|рублей","ж|копейка|копейки|копеек") 'СуммаПрописью(1254.05, "м|метр|метра|метров","м|сантиметр|сантиметра|сантиметров|3") 'СуммаПрописью(10, "с|очко|очка|очков","")
Public Function СуммаПрописьюВРублях(sum As Decimal) As String Return СуммаПрописью(sum, "м|рубль|рубля|рублей", "ж|копейка|копейки|копеек") End Function
Public Function СуммаПрописьюВДолларах(sum As Decimal) As String Return СуммаПрописью(sum, "м|доллар|доллара|долларов", "м|цент|цента|центов") End Function
Public Function СуммаПрописьюВЕвро(sum As Decimal) As String Return СуммаПрописью(sum, "м|евро|евро|евро", "м|цент|цента|центов") End Function
Public Function СуммаПрописью( _ sum As Decimal, _ intvalue As String, _ decvalue As String, _ Optional showIntIfNull As Boolean = True, _ Optional showDecIfNull As Boolean = True, _ Optional decToWord As Boolean = False _ ) As String
'showIntIfNull - переменная отвечающая за отображение целых, если они равны нулю - если True, то показывать, иначе - не показывать. 'decToWord - переменная отвечающая за отображение десятичных - если True, то десятичные тоже будут переведены в слова, иначе - останутся цифры.
Dim countDecDigit As Integer = 2 'Количество цифр после запятой, по умолчанию для валют - 2 Dim intValues() As String = intvalue.Split("|") Dim decValues() As String = decvalue.Split("|") If decValues.Count = 5 Then 'Если задан иное количество цифр после запятой, то присваиваем новое значение.
' Например если нужно сделать 3,256 метров - и получить 256 см, то количество цифр после запятой - 3. ' В этом случае вызов функции будет выглядеть - СуммаПрописью(1254.05, "м|метр|метра|метров","м|сантиметр|сантиметра|сантиметров|3")
If Val(decValues(4)) >= 0 AndAlso Str(Val(decValues(4))).Trim = Val(decValues(4)) Then countDecDigit = Val(decValues(4)) End If End If
'Разделяем целую часть и дробную часть '====================================================================================== 'Обрабатываем целую часть числа '======================================================================================
Dim sumInt As Decimal = Int(sum) 'Получаем целую часть Dim intStr As String = "" If Not (sumInt = 0 And Not showIntIfNull) Then intStr = ПолучитьЧислоПрописьюСВалютой(sumInt, intvalue) 'Получаем целую часть прописью End If
'====================================================================================== 'Обрабатываем дробную часть числа '======================================================================================
Dim sumDec As Decimal = sum - sumInt 'Получаем дробную часть, приводим её к целому виду sumDec = Math.Round(sumDec * 10 ^ countDecDigit) 'Отсекаем ненужные цифры в зависимости от заданного порядка. ' Вместо Int() используем Math.Round(), так как нам нужно корректное округление. Dim decStr As String = "" If Not (sumDec = 0 And Not showDecIfNull) Then If decToWord Then 'Нужно преобразовать в слова decStr = ПолучитьЧислоПрописьюСВалютой(sumDec, decvalue) 'Получаем десятичную часть прописью Else 'Оставить цифры как есть decStr = CInt(sumDec).ToString + " " + ПолучитьПадежВалюты(sumDec, decvalue) 'Получаем десятичную часть прописью End If End If Return (intStr.Trim + " " + decStr.Trim).Trim End Function
Public Function ЧислоПрописью( _ sum As Decimal, _ Optional countDecDigit As Integer = 0, _ Optional showIntIfNull As Boolean = True, _ Optional showDecIfNull As Boolean = True, _ Optional decToWord As Boolean = True _ ) As String
'countDecDigit - переменная форсированно определяющая количество цифр после запятой. Если 0, то автоматически. 'showIntIfNull - переменная отвечающая за отображение целых, если они равны нулю - если True, то показывать, иначе - не показывать. 'decToWord - переменная отвечающая за отображение десятичных - если True, то десятичные тоже будут переведены в слова, иначе - останутся цифры.
Dim intvalue As String = "ж|целая|целых|целых" Dim intValues() As String = intvalue.Split("|")
'Разделяем целую часть и дробную часть '====================================================================================== 'Обрабатываем целую часть числа '======================================================================================
Dim sumInt As Decimal = Int(sum) 'Получаем целую часть Dim intStr As String = "" If Not (sumInt = 0 And Not showIntIfNull) Then intStr = ПолучитьЧислоПрописьюСВалютой(sumInt, intvalue) 'Получаем целую часть прописью End If
'====================================================================================== 'Обрабатываем дробную часть числа '======================================================================================
Dim sumDec As Decimal = sum - sumInt 'Получаем дробную часть, приводим её к целому виду Dim i As Integer = 0 If countDecDigit <= 0 Then Do i += 1 If Int(sumDec * 10 ^ i) / 10 ^ i = sumDec Or i = 10 Then sumDec = sumDec * 10 ^ i Exit Do End If Loop Else If countDecDigit > 10 Then countDecDigit = 10 sumDec = Math.Round(sumDec * 10 ^ countDecDigit) 'Отсекаем ненужные цифры в зависимости от заданного порядка. ' Вместо Int() используем Math.Round(), так как нам нужно корректное округление. i = countDecDigit End If Dim decStr As String = "" If Not (sumDec = 0 And Not showDecIfNull) Then Dim curDecName As String = numbersDec(ПолучитьИндексПадежаПоЧислу(sumDec) * 10 + i - 1) If decToWord Then 'Нужно преобразовать в слова decStr = ПолучитьЧислоПрописью(sumDec, "ж") + curDecName 'Получаем десятичную часть прописью Else 'Оставить цифры как есть decStr = CInt(sumDec).ToString + " " + curDecName 'Получаем десятичную часть прописью End If End If Return (intStr.Trim + " " + decStr.Trim).Trim End Function
Public Function ПолучитьМассивТроек(sum As Decimal) As Integer() Dim arr() As Integer = {} Dim i As Integer = 0 Do i += 1 Dim value As Integer = Int((CDec(sum / 1000 ^ i) - CDec(Int(sum / 1000 ^ i))) * 1000) 'Необходимо преобразование в Decimal, иначе происходит 'преобразование в Double и возникают различные коллизии, например вместо 0.454 получается 0.45399999 и при округлении искажаются числа. ReDim Preserve arr(arr.Length) arr(arr.Length - 1) = value Loop While sum / 1000 ^ i >= 1 Return arr End Function
Private Function ПолучитьСтрокуТройкиСПорядком(sum As Integer, period As Integer, rod As String) As String Dim strInt As String = "" Dim digits() As Integer = {Int(sum / 100), Int(sum / 10) - Int(sum / 100) * 10, sum - Int(sum / 10) * 10} For i As Integer = 0 To 2 If digits(i) > 0 Then If i = 0 Then 'Добавляем сотни strInt += numbers100(digits(i)) + " " ElseIf i = 1 Then 'Добавляем десятки If digits(i) > 1 Then 'Все стандартно - добавляем двадцать, пятьдесят и т.д. strInt += numbers10(digits(i)) + " " Else 'А вот здесь уже "форс-мажор" - от одиннадцати до девятнадцати. strInt += numbers10_20(digits(2)) + " " 'И здесь необходимо выйти из цикла Exit For End If ElseIf i = 2 Then 'Добавляем единицы - и здесь обязательно нужно учитывать род! 'У нас есть род - rod Dim index As Integer = IIf(rod = "c", 20, IIf(rod = "ж", 10, 0)) strInt += numbers1(digits(i) + index) + " " 'один, одна или одно! End If End If Next If period >= 0 And period < periods_m.Length / 3 Then Dim indexPer As Integer = ПолучитьИндексПадежа(digits(2), digits(1)) strInt += periods_m(period + indexPer * 5) End If Return strInt End Function
Private Function ПолучитьИндексПадежа(lastDigit As Integer, prevDigit As Integer) As Integer Dim indexPer As Integer = 0 'Именительный падеж If {2, 3, 4}.Contains(lastDigit) And prevDigit <> 1 Then indexPer = 1 'Родительный падеж If {0, 5, 6, 7, 8, 9}.Contains(lastDigit) Or prevDigit = 1 Then indexPer = 2 'Родительный падеж, множественное число Return indexPer End Function
Public Function ПолучитьИндексПадежаПоЧислу(sum As Decimal) As Integer Dim digits() As Integer = {Int(sum / 10) - Int(sum / 100) * 10, sum - Int(sum / 10) * 10} Return ПолучитьИндексПадежа(digits(1), digits(0)) End Function
Private Function ПолучитьЧислоПрописью(sum As Decimal, rod As String) As String Dim sumStr As String = ""
'Необходимо разбить целую часть на тройки периодов, например 'из 25 045 145 002 нам необходимо получить массив 'array={25,45,145,2}
Dim arrInt3() As Integer = ПолучитьМассивТроек(sum) 'Инвертируем массив, так как нам нужно начинать с больших порядков - сначала миллиарды, потом миллионы, потом тысячи... Array.Reverse(arrInt3) If arrInt3.Length = 1 And arrInt3(0) = 0 Then 'На вход подано некорректное число - меньше единицы, дробное, либо ноль. sumStr += numbers1(0) + " " Else 'Собираем массив в кучу по порядку, индекс массива укажет на порядок - тысячи, миллионы, миллиарды и т.д. For i As Integer = 0 To arrInt3.Length - 1 If arrInt3(i) > 0 Then 'Только если тройка значима - обрабатываем её Dim rodPeriodInt As String = rod 'Получаем род периода If arrInt3.Length - 2 - i >= 0 AndAlso rodPeriodInt.Length > arrInt3.Length - 2 - i Then rodPeriodInt = periods_m_rod(arrInt3.Length - 2 - i) 'В случае необходимости корректируем род периода, например - у тысяч - род женский sumStr += ПолучитьСтрокуТройкиСПорядком(arrInt3(i), arrInt3.Length - 2 - i, rodPeriodInt) If sumStr.Length > 0 AndAlso sumStr.Last <> " " Then sumStr += " " End If Next End If Return sumStr End Function
Private Function ПолучитьЧислоПрописьюСВалютой(sum As Decimal, curValues_ As String) As String Dim strSum As String = "" 'Переменная, в которой будет храниться текстовое значение Dim curValues() As String = curValues_.Split("|") Dim currencyName As String = "" 'Наименование целых частей валюты Dim rod As String = "м" If curValues.Length > 0 Then rod = curValues(0) 'Определяем род валюты, если он определен в переменной curValues_ Dim curIntNameIndex As Integer = ПолучитьИндексПадежаПоЧислу(sum) + 1 'Из заданного массива 'м|метр|метра|метров' получаем индекс падежа. If curValues.Length > curIntNameIndex Then currencyName = curValues(curIntNameIndex) strSum = ПолучитьЧислоПрописью(sum, rod) strSum += currencyName 'Здесь можно заменить на intValues(ПолучитьИндексПадежаПоЧислу(sum) + 1) Return strSum End Function
Private Function ПолучитьПадежВалюты(sum As Decimal, curValues_ As String) As String Dim curValues() As String = curValues_.Split("|") Dim currencyName As String = "" 'Наименование целых частей валюты Dim curIntNameIndex As Integer = ПолучитьИндексПадежаПоЧислу(sum) + 1 'Из заданного массива 'м|метр|метра|метров' получаем индекс падежа. If curValues.Length > curIntNameIndex Then currencyName = curValues(curIntNameIndex) Return currencyName End Function
#End Region
06

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

07

Похожие запросы:

  • Сумма прописью в отчетах
  • Как вывести в отчете итоговые цифры ПРОПИСЬЮ
  • Функция для написания суммы прописью
  • Запись числа прописью
  • Сумма прописью. Как реализовать
  • Преобразование числа в текст
comments powered by HyperComments

Яндекс.Метрика