Как-то раз мне понадобилось написать генерацию суммы прописью для одного проекта. Поиск готовых решений ни к чему не привел, в результате родился маленький С++ класс, генерирующий прописной эквивалент числа. В качестве приятного бонуса я добавил туда поддержу рублей и долларов (это требовалось для того проекта). Под катом немного теории и ссылка на Git-репозиторий.
В русском языке числа от 1 до 9 (так называемые единицы) и от 10 до 20 (второй ряд единиц) имеют индивидуальные названия. После 20 индивидуальные названия имеют десятки, а число образуется путем прибавления к названию десятки числа категории из категории единиц.
Пример:
Сотни включают в себя десятки и единицы, а тысячи содержат в себе все вышеперечисленные названия. И так по мере нарастания порядка числа, то есть каждый новый порядок включает в себя все предыдущие.
Тут есть следующая особенность. При формировании числа меньше 100 проблем нет, но при формировании прописного эквивалента больших сумм у вас появляются слова, обозначающие порядки сотен, десятов и единиц, а именно тысячи, миллионы и т.д.
Возникают такие варианты чисел:
и т.п.
Правила такие:
Пример:
Зная эти особенности, мжно составить логику работы генератора прописного числа.
Механизм генерации числа работает следующим образом:
Так и родился C++ класс Propis. Из double значения на выходе получается строка с прописным значением и валютой числа (при наличии) с точностью до сотых. Реализована генерация чисел до 1 миллиарда, при необходимости можно легко сделать поддержку миллиардов и выше. Зависит только от стандартной библиотеки cmath и std::string.
Пример использования в C++ коде:
Пример использования в iOS-программе:
Git-репозиторий с исходным кодом класса находится здесь. Буду рад если кому-то пригодится.
Теория
Названия чисел
В русском языке числа от 1 до 9 (так называемые единицы) и от 10 до 20 (второй ряд единиц) имеют индивидуальные названия. После 20 индивидуальные названия имеют десятки, а число образуется путем прибавления к названию десятки числа категории из категории единиц.
Пример:
- 5 — пять
- 17 — семнадцать
- 23 — двадцать три
- 48 — сорок восемь
Сотни включают в себя десятки и единицы, а тысячи содержат в себе все вышеперечисленные названия. И так по мере нарастания порядка числа, то есть каждый новый порядок включает в себя все предыдущие.
Женский и мужской род названий порядков
Тут есть следующая особенность. При формировании числа меньше 100 проблем нет, но при формировании прописного эквивалента больших сумм у вас появляются слова, обозначающие порядки сотен, десятов и единиц, а именно тысячи, миллионы и т.д.
Возникают такие варианты чисел:
- одна тысяча
- один миллион
- два миллиона
- две тысячи
- пять тысяч
и т.п.
Правила такие:
- Для названий порядков женского рода приходится модифицировать 1 и 2 (одна, две);
- Для обоих родов по-разному склоняются окончания названий порядков для числа 1, группы от 2 до 4 и далее до 20 (включая второй ряд единиц от 11 до 19).
Пример:
- 1 (одна) тысяча
- 2-3-4 тысячи
- 5-19 тысяч
- 1 миллион
- 2-3-4 миллиона
- 5-20 миллионов
Зная эти особенности, мжно составить логику работы генератора прописного числа.
Класс
Механизм генерации числа работает следующим образом:
- Получив на входе число, определяем разряд числа (миллионы, тысячи или меньше);
- Для каждого порядка кроме генерируем сотни, десятки и единицы, дописывая в конце название порядка.
Так и родился C++ класс Propis. Из double значения на выходе получается строка с прописным значением и валютой числа (при наличии) с точностью до сотых. Реализована генерация чисел до 1 миллиарда, при необходимости можно легко сделать поддержку миллиардов и выше. Зависит только от стандартной библиотеки cmath и std::string.
Пример использования в C++ коде:
Propis *propis = new Propis;
double value = 345.12;
// Задаем число для генерации и тип валюты
std::string resultString = propis->conv(value, Propis::Dollar);
// "триста сорок пять долларов, двенадцать центов"
Пример использования в iOS-программе:
- (IBAction)valueChanged:(UITextField *)sender
{
Propis propis;
double value = [sender.text doubleValue];
std::string stdResultString = propis.conv(value, Propis::NoCurrency);
NSString *resultString = [NSString stringWithUTF8String:stdResultString.c_str()];
self.resultView.text = resultString;
}
Git-репозиторий с исходным кодом класса находится здесь. Буду рад если кому-то пригодится.