Пришла необходимость добавить в систему отображение цифр, а конкретнее цен в счетах, в прописном виде.
т.е. "100.00" переводим в "Сто рублей 00 копеек."
Долго не мудрствуя обратился к Google'у. Наткнулся на простенький и тем привлекательный код автора называющего себя runcore. Спасибо ему большое. Абсолютно честно сплагиатил у него, немного изменив под себя.
Все что я до этого находил было либо перегружено возможностями, такими как отображение разных валют, и потому разбираться не особо хотелось. Либо код был настолько "быдло", что рассматривать его просто было противно.
Привожу код здесь.
/**
* Класс для работы с деньгами
* @author runcore
*/
import java.util.ArrayList;
import java.util.Collections;
import java.math.BigDecimal;
public class NumToStrMoney {
/**
* Сумма денег
*/
private BigDecimal amount;
/**
* Конструктор из Long
*/
public NumToStrMoney(long l) {
String s = String.valueOf(l);
if (!s.contains(".")) {
s += ".0";
}
this.amount = new BigDecimal(s);
}
/**
* Конструктор из Double
*/
public NumToStrMoney(double l) {
String s = String.valueOf(l);
if (!s.contains(".")) {
s += ".0";
}
this.amount = new BigDecimal(s);
}
/**
* Конструктор из String
*/
public NumToStrMoney(String s) {
if (!s.contains(".")) {
s += ".0";
}
this.amount = new BigDecimal(s);
}
/**
* Вернуть сумму как строку
*/
public String asString() {
return amount.toString();
}
/**
* Вернуть сумму прописью, с точностью до копеек
*/
public String num2str() {
return num2str(false);
}
/**
* Выводим сумму прописью
* @param stripkop boolean флаг - показывать копейки или нет
* @return String Сумма прописью
*/
public String num2str(boolean stripkop) {
String[][] sex = {
{"", "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять"},
{"", "одна", "две", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять"},};
String[] str100 = {"", "сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот"};
String[] str11 = {"", "десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать", "двадцать"};
String[] str10 = {"", "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто"};
String[][] forms = {
{"копейка", "копейки", "копеек", "1"},
{"рубль", "рубля", "рублей", "0"},
{"тысяча", "тысячи", "тысяч", "1"},
{"миллион", "миллиона", "миллионов", "0"},
{"миллиард", "миллиарда", "миллиардов", "0"},
{"триллион", "триллиона", "триллионов", "0"}, // можно добавлсть дальше секстиллионы и т.д.
};
// получаем отдельно рубли и копейки
long rub = amount.longValue();
String[] moi = amount.toString().split("\\.");
long kop = Long.valueOf(moi[1]);
if (!moi[1].substring(0, 1).equals("0")) {// начинаетсс не с нулс
if (kop < 10) {
kop *= 10;
}
}
String kops = String.valueOf(kop);
if (kops.length() == 1) {
kops = "0" + kops;
}
long rub_tmp = rub;
// Разбиватель суммы на сегменты по 3 цифры с конца
ArrayList segments = new ArrayList();
while (rub_tmp > 999) {
long seg = rub_tmp / 1000;
segments.add(rub_tmp - (seg * 1000));
rub_tmp = seg;
}
segments.add(rub_tmp);
Collections.reverse(segments);
// снализируем сегменты
String o = "";
if (rub == 0) {// если соль
o = "ноль " + morph(0, forms[1][0], forms[1][1], forms[1][2]);
if (stripkop) {
return o;
} else {
return o + " " + kop + " " + morph(kop, forms[0][0], forms[0][1], forms[0][2]);
}
}
// Больше нуля
int lev = segments.size();
for (int i = 0; i < segments.size(); i++) {// перебираем сегменты
int sexi = (int) Integer.valueOf(forms[lev][3].toString());// определсем род
int ri = (int) Integer.valueOf(segments.get(i).toString());// текущий сегмент
if (ri == 0 && lev > 1) {// если сегмент ==0 И не последний уровень(там Units)
lev--;
continue;
}
String rs = String.valueOf(ri); // число в строку
// нормализация
if (rs.length() == 1) {
rs = "00" + rs;// два нулика в префикс?
}
if (rs.length() == 2) {
rs = "0" + rs; // или лучше один?
}// получаем циферки длс анализа
int r1 = (int) Integer.valueOf(rs.substring(0, 1)); //первас цифра
int r2 = (int) Integer.valueOf(rs.substring(1, 2)); //вторас
int r3 = (int) Integer.valueOf(rs.substring(2, 3)); //третьс
int r22 = (int) Integer.valueOf(rs.substring(1, 3)); //вторас и третьс
// Супер-нано-анализатор циферок
if (ri > 99) {
o += str100[r1] + " "; // Сотни
}
if (r22 > 20) {// >20
o += str10[r2] + " ";
o += sex[sexi][r3] + " ";
} else { // <=20
if (r22 > 9) {
o += str11[r22 - 9] + " "; // 10-20
} else {
o += sex[sexi][r3] + " "; // 0-9
}
}
// Единицы измерения (рубли...)
o += morph(ri, forms[lev][0], forms[lev][1], forms[lev][2]) + " ";
lev--;
}
// Копейки в цифровом виде
if (stripkop) {
o = o.replaceAll(" {2,}", " ");
} else {
o = o + "" + kops + " " + morph(kop, forms[0][0], forms[0][1], forms[0][2]);
o = o.replaceAll(" {2,}", " ");
}
return o;
}
/**
* Склонсем словоформу
* @param n Long количество объектов
* @param f1 String вариант словоформы длс одного объекта
* @param f2 String вариант словоформы длс двух объектов
* @param f5 String вариант словоформы длс псти объектов
* @return String правильный вариант словоформы длс указанного количества объектов
*/
public static String morph(long n, String f1, String f2, String f5) {
n = Math.abs(n) % 100;
long n1 = n % 10;
if (n > 10 && n < 20) {
return f5;
}
if (n1 > 1 && n1 < 5) {
return f2;
}
if (n1 == 1) {
return f1;
}
return f5;
}
public static void main(String[] args) {
NumToStrMoney ntsm = new NumToStrMoney(15555.48);
System.out.println(ntsm.asString());
System.out.println(ntsm.num2str(true));
System.out.println(ntsm.num2str());
}
}В трейсе после запуска получим следующее
run-main:
15555.48
пятнадцать тысяч пятьсот пятьдесят пять рублей
пятнадцать тысяч пятьсот пятьдесят пять рублей 48 копеек
Что обычно и требуется дл небольших проектов.