Пришла необходимость добавить в систему отображение цифр, а конкретнее цен в счетах, в прописном виде.
т.е. "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());
}
}
В трейсе после запуска получим следующее
Что обычно и требуется дл небольших проектов.
т.е. "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 копеек
15555.48
пятнадцать тысяч пятьсот пятьдесят пять рублей
пятнадцать тысяч пятьсот пятьдесят пять рублей 48 копеек
Что обычно и требуется дл небольших проектов.