Страницы

Поиск по вопросам

суббота, 30 ноября 2019 г.

Java реализация суммы прописью

#java #java_ee


Существует ли библиотечная реализация перевода суммы в слова на русском языке? Если
нет, то как реализовать оптимальным способом?
    


Ответы

Ответ 1



Можете воспользоваться готовой библиотекой Icu4j: RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("ru"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("pl"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // jeden milion dwieście trzydzieści cztery tysiące pięćset sześćdziesiąt siedem RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("en"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // one million two hundred thirty-four thousand five hundred sixty-seven RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("de"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // eine Million zwei-hundert-vier-und-dreißig-tausend-fünf-hundert-sieben-und-sechzig

Ответ 2



Использую этот класс. Можно поискать еще что-то подобное на github package net.sf.lab3f.util; import java.util.Stack; public class RussianMoney { private static enum Ranges {UNITS, DECADES, HUNDREDS, THOUSANDS, MILLIONS, BILLIONS}; private static Stack threeChars; private static class ThreeChar { char h, d, u; Ranges range; } public static String digits2Text(Double d){ if(d == null || d < 0.0) return null; String s = d.toString(); int n = s.length() - s.lastIndexOf('.'); if(n > 3) return null; if(n == 2) s += "0"; String[] sa = s.split("\\."); threeChars = new Stack (); threeChars.push(new ThreeChar()); threeChars.peek().range = Ranges.UNITS; StringBuilder sb = new StringBuilder(sa[0]).reverse(); for(int i = 0; i < sb.length(); i++){ if(i > 0 && i % 3 == 0){ threeChars.push(new ThreeChar()); } ThreeChar threeChar = threeChars.peek(); switch(i){ case 0: threeChar.u = sb.charAt(i); break; case 3: threeChar.range = Ranges.THOUSANDS; threeChar.u = sb.charAt(i); break; case 6: threeChar.range = Ranges.MILLIONS; threeChar.u = sb.charAt(i); break; case 9: threeChar.range = Ranges.BILLIONS; threeChar.u = sb.charAt(i); break; case 2: case 5: case 8: threeChar.h = sb.charAt(i); break; default: threeChar.d = sb.charAt(i); } } StringBuilder result = new StringBuilder(); while(!threeChars.isEmpty()){ ThreeChar thch = threeChars.pop(); if(thch.h > 0 ){ result.append(getHundreds(thch.h)); result.append(' '); } if(thch.d > '0'){ if(thch.d > '1' || (thch.d == '1' && thch.u == '0')) result.append(getDecades(thch.d)); else if(thch.d > '0') result.append(getTeens(thch.d)); result.append(' '); } if(thch.u > '0' && thch.d != '1'){ result.append(getUnits(thch.u, thch.range == Ranges.THOUSANDS)); result.append(' '); } switch(thch.range){ case BILLIONS: if(thch.d == '1' || thch.u == '0') result.append("миллиардов"); else if(thch.u > '4')result.append("миллиардов"); else if(thch.u > '1')result.append("миллиарда"); else result.append("миллиард"); break; case MILLIONS: if(thch.d == '1' || thch.u == '0') result.append("миллионов"); else if(thch.u > '4')result.append("миллионов"); else if(thch.u > '1')result.append("миллиона"); else result.append("миллион"); break; case THOUSANDS: if(thch.d == '1' || thch.u == '0') result.append("тысяч"); else if(thch.u > '4')result.append("тысяч"); else if(thch.u > '1')result.append("тысячи"); else result.append("тысяча"); break; default: if(thch.d == '1' || thch.u == '0' || thch.u > '4')result.append("рублей"); else if(thch.u > '1')result.append("рубля"); else result.append("рубль"); } result.append(' '); } result.append(sa[1] + ' '); switch(sa[1].charAt(1)){ case '1': result.append(sa[1].charAt(0) != '1' ? "копейка" : "копеек"); break; case '2': case '3': case '4': result.append(sa[1].charAt(0) != '1' ? "копейки" : "копеек"); break; default: result.append("копеек"); } char first = Character.toUpperCase(result.charAt(0)); result.setCharAt(0, first); return result.toString(); } private static String getHundreds(char dig){ switch(dig){ case '1': return "сто"; case '2': return "двести"; case '3': return "триста"; case '4': return "четыреста"; case '5': return "пятьсот"; case '6': return "шестсот"; case '7': return "семсот"; case '8': return "восемсот"; case '9': return "девятьсот"; default: return null; } } private static String getDecades(char dig){ switch(dig){ case '1': return "десять"; case '2': return "двадцать"; case '3': return "тридцать"; case '4': return "сорок"; case '5': return "пятьдесят"; case '6': return "шестьдесят"; case '7': return "семьдесят"; case '8': return "восемьдесят"; case '9': return "девяносто"; default: return null; } } private static String getUnits(char dig, boolean female){ switch(dig){ case '1': return female ? "одна" : "один"; case '2': return female ? "две" : "два"; case '3': return "три"; case '4': return "четыре"; case '5': return "пять"; case '6': return "шесть"; case '7': return "семь"; case '8': return "восемь"; case '9': return "девять"; default: return null; } } private static String getTeens(char dig){ String s = ""; switch(dig){ case '1': s = "один"; break; case '2': s = "две"; break; case '3': s = "три"; break; case '4': s = "четыр"; break; case '5': s = "пят"; break; case '6': s = "шест"; break; case '7': s = "сем"; break; case '8': s = "восем"; break; case '9': s = "девят"; break; } return s + "надцать"; } public static void main(String[] args){ System.out.println(new RussianMoney().digits2Text(new Double(args[0]))); } }

Ответ 3



Тема старая, но предлагаю еще один вариант(с рекурсией) : /** * Класс для преобразования double-числа в рубли-копейки прописью * @author Segr88 */ public class MoneyInWords { private static final String dig1[][] = {{"одна", "две", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять"}, {"один", "два"}}; //dig[0] - female, dig[1] - male private static final String dig10[] = {"десять","одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"}; private static final String dig20[] = {"двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто"}; private static final String dig100[] = {"сто","двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот"}; private static final String leword[][] = { {"копейка", "копейки", "копеек", "0"}, {"рубль", "рубля", "рублей", "1"}, {"тысяча", "тысячи", "тысяч", "0"}, {"миллион", "миллиона", "миллионов", "1"}, {"миллиард", "миллиарда", "миллиардов", "1"}, {"триллион", "триллиона", "триллионов", "1"}}; //рекурсивная функция преобразования целого числа num в рубли private static String num2words(long num, int level) { StringBuilder words = new StringBuilder(50); if (num==0) words.append("ноль "); //исключительный случай int sex = leword[level][3].indexOf("1")+1; //не красиво конечно, но работает int h = (int)(num%1000); //текущий трехзначный сегмент int d = h/100; //цифра сотен if (d>0) words.append(dig100[d-1]).append(" "); int n = h%100; d = n/10; //цифра десятков n = n%10; //цифра единиц switch(d) { case 0: break; case 1: words.append(dig10[n]).append(" "); break; default: words.append(dig20[d-2]).append(" "); } if (d==1) n=0; //при двузначном остатке от 10 до 19, цифра едициц не должна учитываться switch(n) { case 0: break; case 1: case 2: words.append(dig1[sex][n-1]).append(" "); break; default: words.append(dig1[0][n-1]).append(" "); } switch(n) { case 1: words.append(leword[level][0]); break; case 2: case 3: case 4: words.append(leword[level][1]); break; default: if((h!=0)||((h==0)&&(level==1))) //если трехзначный сегмент = 0, то добавлять нужно только "рублей" words.append(leword[level][2]); } long nextnum = num/1000; if(nextnum>0) { return (num2words(nextnum, level+1) + " " + words.toString()).trim(); } else { return words.toString().trim(); } } //функция преобразования вещественного числа в рубли-копейки //при значении money более 50-70 триллионов рублей начинает искажать копейки, осторожней при работе такими суммами public static String inwords(double money) { if (money<0.0) return "error: отрицательное значение"; String sm = String.format("%.2f", money); String skop = sm.substring(sm.length()-2, sm.length()); //значение копеек в строке int iw; switch(skop.substring(1)) { case "1": iw = 0; break; case "2": case "3": case "4": iw = 1; break; default: iw = 2; } long num = (long)Math.floor(money); if (num<1000000000000000l) { return num2words(num, 1) + " " + skop + " " + leword[0][iw]; } else return "error: слишком много рублей " + skop + " " + leword[0][iw]; } } Пример использования: System.out.println(MoneyInWords.inwords(67382645834.35)); Вывод: шестьдесят семь миллиардов триста восемьдесят два миллиона шестьсот сорок пять тысяч восемьсот тридцать четыре рубля 35 копеек

Ответ 4



На geektimes есть вариант готовой реализации: import java.util.ArrayList; import java.util.Collections; import java.math.BigDecimal; /** * Класс для работы с деньгами * @author runcore */ public class fwMoney { /** * Сумма денег */ private BigDecimal amount; /** * Конструктор из Long */ public fwMoney(long l) { String s = String.valueOf(l); if (!s.contains(".") ) s += ".0"; this.amount = new BigDecimal( s ); } /** * Конструктор из Double */ public fwMoney(double l) { String s = String.valueOf(l); if (!s.contains(".") ) s += ".0"; this.amount = new BigDecimal( s ); } /** * Конструктор из String */ public fwMoney(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; i1) {// если сегмент ==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; } } Пример использования: fwMoney mo = new fwMoney(«7654321.98»); String money_as_string = mo.num2str(); Результат: "семь миллионов шестьсот пятьдесят четыре тысячи триста двадцать один рубль 98 копеек"

Ответ 5



тоже тренировался и сделал по своему import java.util.Scanner; public class NumberToText { // Перевод числа в диапазоне -999 - 999 в текстовую форму private static int billion; private static int million; private static int thousand; private static int toThousand; private static long numberA; private static long numberMax = 999999999999L ; // private int numericalValue; private static String numText;// число в виде текста //private int index ; private static int indexA; private static int units; // единичные значение private static int decimal; // десятичное значение private static int hundreds; // сотни private static final String[][]sampleText ={ {"","од","дв","три","четыре","пять","шесть","семь","восемь","девять"}, {"", "десять " ,"двадцать ","тридцать ","сорок ","пятьдесят ","шестьдесят ","семьдесят ","восемьдесят ","девяносто "}, {"","сто ","двести ","триста ","четыреста ","пятьсот ","шестьсот ","семьсот ","восемьсот ","девятьсот "} }; private static final String[]sample11to19 = { "десять ", "одинадцать ", "двенадцать ", "тринадцать ", "четырнадцать ","пятнадцать ", "шеснадцать ", "семьнадцать ", "восемьнадцать ", "девятнадцать ", "девятнадцать "} ; private static final String[][] textMillion={{"","","",""}, {"миллиардов ","миллионов ","тысячь ",""}, {"миллиард ","миллион ","тысяча ",""}, {"миллиарда ","миллиона ","тысячи ",""}, {"миллиардов ","миллионов ","тысячь ",""}}; public static String WordsRus (long number) { numberA = number; numText =""; if (numberA < -numberMax || numberA > numberMax ) { return numText = "Число выходит за рамки указанного диапазона";} if (numberA == 0 ) { return numText = "ноль ";} if (number < 0) {numText = "минус "; numberA = -numberA;} //делаем позитивное значение number // разбиваем число на миллиарды,миллионы,тысячи и единицы billion = (int) ( numberA / 1000000000); million = (int) (numberA-(billion*1000000000))/ 1000000 ; thousand = (int) (numberA - (billion*1000000000)-(million*1000000)) / 1000; toThousand = (int)(numberA % 1000) ; // формируем текст числа прописью numText =numText + WordsToThousand (billion , 0)+WordsToThousand (million , 1)+WordsToThousand (thousand , 2)+WordsToThousand (toThousand , 3); return numText ; } private static String WordsToThousand ( int numericalValue , int index ){ //this.numericalValue = numericalValue; //this.index = index; // разбиваем образец числа на составляющие hundreds = numericalValue / 100; decimal = (numericalValue - (hundreds*100) ) / 10; units = numericalValue % 10 ; // формируем число без степени числа numText = ""; if ( decimal == 1 ) numText = sampleText [2] [hundreds] + sample11to19 [units]; else numText = sampleText [2] [hundreds] + sampleText [1][decimal] + sampleText [0] [units]; // формируем окончания в единицах if (index == 2) {if (units == 1 && decimal != 1) numText = numText + "на "; else if (units == 2 & decimal != 1) numText = numText + "е "; if (units > 1 && decimal != 1) numText = numText + " ";} else {if (units == 1 && decimal != 1) numText = numText + "ин "; if (units == 2 & decimal != 1) {numText = numText + "а ";} else if (units != 0 & decimal != 1) numText = numText + " ";} // дописываем степень числа indexA = 0; if (numericalValue != 0 ) { if (units == 0 || decimal == 1 ) indexA = 1; else if (units == 1) indexA = 2; else if (units > 1 & units < 5) indexA = 3; else indexA = 4;} numText = numText + textMillion [indexA][index]; return numText; } } public class Dialog { public static void main(String[] args) { long number;// введенное число Scanner in = new Scanner(System.in); do { System.out.print("Введите целое число в диапазоне -999 999 999 999 до 999 999 999 999, для выхода введите 0: "); number = (long) in.nextDouble(); System.out.println(NumberToText.WordsRus(number)); } while ( number != 0); System.out.println("Введено число /Ноль/ Работа программы завершена"); } }

Комментариев нет:

Отправить комментарий