Как стать автором
Обновить

Сумма прописью на Java

Время на прочтение11 мин
Количество просмотров14K
Здравствуйте.

Буду краток.
Понадобилось «по работе» выводить в отчетах сумму прописью. Проект на Java. Посмотрев что есть готового, как всегда, пришел в выводу что «своя рубашка ближе к телу». К тому же хотелось именно самому написать, набраться опыта, так как на Java перешел не так давно…

Матерые явисты уже давно нашли или сами решили подобную задачу, а начинающим, возможно, пригодится:


Copy Source | Copy HTML
  1. import java.util.ArrayList;
  2. import java.util.Collections;
  3. import java.math.BigDecimal;
  4.  
  5. /**<br/> * Класс для работы с деньгами<br/> * @author runcore<br/> */
  6. public class fwMoney {
  7.  
  8.     /**<br/>     * Сумма денег<br/>     */
  9.     private BigDecimal amount;
  10.  
  11.     /**<br/>     * Конструктор из Long<br/>     */
  12.     public fwMoney(long l) {
  13.         String s = String.valueOf(l);
  14.         if (!s.contains(".") )
  15.             s += ".0";
  16.         this.amount = new BigDecimal( s );
  17.     }
  18.  
  19.     /**<br/>     * Конструктор из Double<br/>     */
  20.     public fwMoney(double l) {
  21.         String s = String.valueOf(l);
  22.         if (!s.contains(".") )
  23.             s += ".0";
  24.         this.amount = new BigDecimal( s );
  25.     }
  26.  
  27.     /**<br/>     * Конструктор из String<br/>     */
  28.     public fwMoney(String s) {
  29.         if (!s.contains(".") )
  30.             s += ".0";
  31.         this.amount = new BigDecimal( s );
  32.     }
  33.  
  34.     /**<br/>     * Вернуть сумму как строку<br/>     */
  35.     public String asString() {
  36.         return amount.toString();
  37.     }
  38.  
  39.     /**<br/>     * Вернуть сумму прописью, с точностью до копеек<br/>     */
  40.     public String num2str() {
  41.         return num2str(false);
  42.     }
  43.  
  44.     /**<br/>     * Выводим сумму прописью<br/>     * @param stripkop boolean флаг - показывать копейки или нет<br/>     * @return String Сумма прописью<br/>     */
  45.     public String num2str(boolean stripkop) {
  46.         String[][] sex = {
  47.             {"","один","два","три","четыре","пять","шесть","семь","восемь","девять"},
  48.             {"","одна","две","три","четыре","пять","шесть","семь","восемь","девять"},
  49.         };
  50.         String[] str100= {"","сто","двести","триста","четыреста","пятьсот","шестьсот","семьсот", "восемьсот","девятьсот"};
  51.         String[] str11 = {"","десять","одиннадцать","двенадцать","тринадцать","четырнадцать", "пятнадцать","шестнадцать","семнадцать","восемнадцать","девятнадцать","двадцать"};
  52.         String[] str10 = {"","десять","двадцать","тридцать","сорок","пятьдесят","шестьдесят", "семьдесят","восемьдесят","девяносто"};
  53.         String[][] forms = {
  54.             {"копейка", "копейки", "копеек", "1"},
  55.             {"рубль", "рубля", "рублей", "0"},
  56.             {"тысяча", "тысячи", "тысяч", "1"},
  57.             {"миллион", "миллиона", "миллионов", "0"},
  58.             {"миллиард","миллиарда","миллиардов","0"},
  59.             {"триллион","триллиона","триллионов","0"},
  60.             // можно добавлять дальше секстиллионы и т.д.
  61.         };
  62.         // получаем отдельно рубли и копейки
  63.         long rub = amount.longValue();
  64.         String[] moi = amount.toString().split("\\.");
  65.         long kop = Long.valueOf(moi[1]);
  66.         if (!moi[1].substring( 0,1).equals("0") ){// начинается не с нуля
  67.             if (kop<10 )
  68.                 kop *=10;
  69.         }
  70.         String kops = String.valueOf(kop);
  71.         if (kops.length()==1 )
  72.             kops = "0"+kops;
  73.         long rub_tmp = rub;
  74.         // Разбиватель суммы на сегменты по 3 цифры с конца
  75.         ArrayList segments = new ArrayList();
  76.         while(rub_tmp>999) {
  77.             long seg = rub_tmp/1000;
  78.             segments.add( rub_tmp-(seg*1000) );
  79.             rub_tmp=seg;
  80.         }
  81.         segments.add( rub_tmp );
  82.         Collections.reverse(segments);
  83.         // Анализируем сегменты
  84.         String o = "";
  85.         if (rub== 0) {// если Ноль
  86.             o = "ноль "+morph( 0, forms[1][ 0],forms[1][1],forms[1][2]);
  87.             if (stripkop)
  88.                 return o;
  89.             else
  90.                 return o +" "+kop+" "+morph(kop,forms[ 0][ 0],forms[ 0][1],forms[ 0][2]);
  91.         }
  92.         // Больше нуля
  93.         int lev = segments.size();
  94.         for (int i= 0; i<segments.size(); i++ ) {// перебираем сегменты
  95.             int sexi = (int)Integer.valueOf( forms[lev][3].toString() );// определяем род
  96.             int ri = (int)Integer.valueOf( segments.get(i).toString() );// текущий сегмент
  97.             if (ri== 0 && lev>1) {// если сегмент ==0 И не последний уровень(там Units)
  98.                 lev--;
  99.                 continue;
  100.             }
  101.             String rs = String.valueOf(ri); // число в строку
  102.             // нормализация
  103.             if (rs.length()==1) rs = "00"+rs;// два нулика в префикс?
  104.             if (rs.length()==2) rs = "0"+rs; // или лучше один?
  105.             // получаем циферки для анализа
  106.             int r1 = (int)Integer.valueOf( rs.substring( 0,1) ); //первая цифра
  107.             int r2 = (int)Integer.valueOf( rs.substring(1,2) ); //вторая
  108.             int r3 = (int)Integer.valueOf( rs.substring(2,3) ); //третья
  109.             int r22= (int)Integer.valueOf( rs.substring(1,3) ); //вторая и третья
  110.             // Супер-нано-анализатор циферок
  111.             if (ri>99) o += str100[r1]+" "; // Сотни
  112.             if (r22>20) {// >20
  113.                 o += str10[r2]+" ";
  114.                 o += sex[ sexi ][r3]+" ";
  115.             }
  116.             else { // <=20
  117.                 if (r22>9) o += str11[r22-9]+" "; // 10-20
  118.                 else o += sex[ sexi ][r3]+" "; // 0-9
  119.             }
  120.             // Единицы измерения (рубли...)
  121.             o += morph(ri, forms[lev][ 0],forms[lev][1],forms[lev][2])+" ";
  122.             lev--;
  123.         }
  124.         // Копейки в цифровом виде
  125.         if (stripkop) {
  126.             o = o.replaceAll(" {2,}", " ");
  127.         }
  128.         else {
  129.             o = o+""+kops+" "+morph(kop,forms[ 0][ 0],forms[ 0][1],forms[ 0][2]);
  130.             o = o.replaceAll(" {2,}", " ");
  131.         }
  132.         return o;
  133.     }
  134.  
  135.     /**<br/>     * Склоняем словоформу<br/>     * @param n Long количество объектов<br/>     * @param f1 String вариант словоформы для одного объекта<br/>     * @param f2 String вариант словоформы для двух объектов<br/>     * @param f5 String вариант словоформы для пяти объектов<br/>     * @return String правильный вариант словоформы для указанного количества объектов<br/>     */
  136.     public static String morph(long n, String f1, String f2, String f5) {
  137.         n = Math.abs(n) % 100;
  138.         long n1 = n % 10;
  139.         if (n > 10 && n < 20) return f5;
  140.         if (n1 > 1 && n1 < 5) return f2;
  141.         if (n1 == 1) return f1;
  142.         return f5;
  143.     }
  144. }


// Использование
// fwMoney mo = new fwMoney(«7654321.98»);
// String money_as_string = mo.num2str();
// семь миллионов шестьсот пятьдесят четыре тысячи триста двадцать один рубль 98 копеек

P.S. В общем ни на что не претендую, просто делюсь тем что получилось.
P.S.1. Как всегда, приветствую конструктивную критику )
P.S.2. Исправил баги + небольшой рефакторинг. Спасибо всем за критику

Теги:
Хабы:
-3
Комментарии9

Публикации

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн