1. 概要

このチュートリアルでは、金額をJavaの単語表現に変換する方法を説明します。

また、外部ライブラリ Tradukisto を介して、カスタム実装がどのように見えるかを確認します。

2. 実装

まず、独自の実装から始めましょう。 最初のステップは、次の要素を使用して2つの文字列配列を宣言することです。

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
};

入力を受け取ったら、無効な値(ゼロと負の値)を処理する必要があります。 有効な入力を受け取ると、ドルとセントの数を変数に抽出できます。

 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];
}

1000未満の数についても同様にこれを行います。

次に、再帰呼び出しを使用して、以下に示すように、100万未満の番号を処理します。

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

同じアプローチは、10億未満の数などにも使用されます。

この変換を行うために呼び出すことができる主なメソッドは次のとおりです。

 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以降のライブラリであり、数値を単語表現に変換するのに役立ちます。 まず、それをプロジェクトにインポートする必要があります(このライブラリの最新バージョンはここにあります):

<dependency>
    <groupId>pl.allegro.finance</groupId>
    <artifactId>tradukisto</artifactId>
    <version>1.0.1</version>
</dependency>

これで、 MoneyConvertersasWords()メソッドを使用して、この変換を行うことができます。

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. 結論

この簡単な記事では、金額を単語に変換する方法について2つのアプローチを見ました。

ここで説明されているすべての例のコード、およびその他の多くのコードは、GitHubにあります。