Отображение суммы денег в словах

Отображение суммы денег в словах

1. обзор

В этом руководстве мы увидим, как мы можем преобразовать денежную сумму в словесное представление на Java.

Мы также увидим, как может выглядеть индивидуальная реализация через внешнюю библиотеку -Tradukisto.

2. Реализация

Начнем с нашей собственной реализации. The first step is to declare two String arrays со следующими элементами:

public static String[] ones = {
  "", "one", "two", "three", "four",
  "five", "six", "seven", "eight",
  "nine", "ten", "eleven", "twelve",
  "thirteen", "fourteen", "fifteen",
  "sixteen", "seventeen", "eighteen",
  "nineteen"
};

public static String[] tens = {
  "",          // 0
  "",          // 1
  "twenty",    // 2
  "thirty",    // 3
  "forty",     // 4
  "fifty",     // 5
  "sixty",     // 6
  "seventy",   // 7
  "eighty",    // 8
  "ninety"     // 9
};

Когда мы получаем ввод, нам нужно будет обработать недопустимые значения (нулевые и отрицательные значения). Once a valid input is received, we can extract the number of dollars and cents into variables:с

 long dollars = (long) money;
 long cents = Math.round((money - dollars) * 100);

Если заданное число меньше 20, то мы получим соответствующий элементones' из массива на основе индекса:

if (n < 20) {
    return ones[(int) n];
}

Мы будем использовать аналогичный подход для чисел меньше 100, но теперь мы должны использовать также массивtens:

if (n < 100) {
    return tens[(int) n / 10]
      + ((n % 10 != 0) ? " " : "")
      + ones[(int) n % 10];
}

Мы делаем это аналогично для чисел, которые меньше одной тысячи.

Далее, мы используем рекурсивные вызовы для работы с номерами, которые меньше миллиона, как показано ниже:

if (n < 1_000_000) {
    return convert(n / 1000) + " thousand" + ((n % 1000 != 0) ? " " : "")
      + convert(n % 1000);
}

Тот же подход используется для чисел менее одного миллиарда и так далее.

Вот основной метод, который можно вызвать для этого преобразования:

 public static String getMoneyIntoWords(double money) {
    long dollars = (long) money;
    long cents = Math.round((money - dollars) * 100);
    if (money == 0D) {
        return "";
    }
    if (money < 0) {
        return INVALID_INPUT_GIVEN;
    }
    String dollarsPart = "";
    if (dollars > 0) {
        dollarsPart = convert(dollars)
          + " dollar"
          + (dollars == 1 ? "" : "s");
    }
    String centsPart = "";
    if (cents > 0) {
        if (dollarParts.length() > 0) {
            centsPart = " and ";
        }
        centsPart += convert(cents) + " cent" + (cents == 1 ? "" : "s");
    }
    return dollarsPart + centsPart;
}

Давайте проверим наш код, чтобы убедиться, что он работает:

@Test
public void whenGivenDollarsAndCents_thenReturnWords() {
    String expectedResult
     = "nine hundred twenty four dollars and sixty cents";

    assertEquals(
      expectedResult,
      NumberWordConverter.getMoneyIntoWords(924.6));
}

@Test
public void whenTwoBillionDollarsGiven_thenReturnWords() {
    String expectedResult
      = "two billion one hundred thirty three million two hundred"
        + " forty seven thousand eight hundred ten dollars";

    assertEquals(
      expectedResult,
      NumberWordConverter.getMoneyIntoWords(2_133_247_810));
}

@Test
public void whenThirtyMillionDollarsGiven_thenReturnWords() {
    String expectedResult
      = "thirty three million three hundred forty eight thousand nine hundred seventy eight dollars";
    assertEquals(
      expectedResult,
      NumberWordConverter.getMoneyIntoWords(33_348_978));
}

Давайте также проверим несколько крайних случаев и убедимся, что мы их тоже учли:

@Test
public void whenZeroDollarsGiven_thenReturnEmptyString() {
    assertEquals("", NumberWordConverter.getMoneyIntoWords(0));
}

@Test
public void whenNoDollarsAndNineFiveNineCents_thenCorrectRounding() {
    assertEquals(
      "ninety six cents",
      NumberWordConverter.getMoneyIntoWords(0.959));
}

@Test
public void whenNoDollarsAndOneCent_thenReturnCentSingular() {
    assertEquals(
      "one cent",
      NumberWordConverter.getMoneyIntoWords(0.01));
}

3. Использование библиотеки

Теперь, когда мы реализовали наш собственный алгоритм, давайте сделаем это преобразование, используя существующую библиотеку.

Tradukisto - это библиотека для Java 8+, которая может помочь нам преобразовать числа в их словесные представления. Во-первых, нам нужно импортировать его в наш проект (последнюю версию этой библиотеки можно найтиhere):


    pl.allegro.finance
    tradukisto
    1.0.1

Теперь мы можем использовать методMoneyConverters ’sasWords() для выполнения этого преобразования:

public String getMoneyIntoWords(String input) {
    MoneyConverters converter = MoneyConverters.ENGLISH_BANKING_MONEY_VALUE;
    return converter.asWords(new BigDecimal(input));
}

Давайте проверим этот метод на простом тестовом примере:

@Test
public void whenGivenDollarsAndCents_thenReturnWordsVersionTwo() {
    assertEquals(
      "three hundred ten £ 00/100",
      NumberWordConverter.getMoneyIntoWords("310"));
}

Мы также могли бы использовать для этого библиотекуICU4J, но она большая и имеет множество других функций, которые выходят за рамки данной статьи.

Однако, посмотрите на это, если нужна поддержка Unicode и глобализации.

4. Заключение

В этой быстрой статье мы увидели два подхода к переводу суммы денег в слова.

Код для всех описанных здесь примеров и многое другое можно найти вover on GitHub.