How to convert number to words in java

379,815

Solution 1

Here is the code, I don't think there is any method in SE.

It basically converts number to string and parses String and associates it with the weight

for example

1000

1 is treated as thousand position and 1 gets mapped to "one" and thousand because of position


This is the code from the website:

English

import java.text.DecimalFormat;

public class EnglishNumberToWords {

  private static final String[] tensNames = {
    "",
    " ten",
    " twenty",
    " thirty",
    " forty",
    " fifty",
    " sixty",
    " seventy",
    " eighty",
    " ninety"
  };

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

  private EnglishNumberToWords() {}

  private static String convertLessThanOneThousand(int number) {
    String soFar;

    if (number % 100 < 20){
      soFar = numNames[number % 100];
      number /= 100;
    }
    else {
      soFar = numNames[number % 10];
      number /= 10;

      soFar = tensNames[number % 10] + soFar;
      number /= 10;
    }
    if (number == 0) return soFar;
    return numNames[number] + " hundred" + soFar;
  }


  public static String convert(long number) {
    // 0 to 999 999 999 999
    if (number == 0) { return "zero"; }

    String snumber = Long.toString(number);

    // pad with "0"
    String mask = "000000000000";
    DecimalFormat df = new DecimalFormat(mask);
    snumber = df.format(number);

    // XXXnnnnnnnnn
    int billions = Integer.parseInt(snumber.substring(0,3));
    // nnnXXXnnnnnn
    int millions  = Integer.parseInt(snumber.substring(3,6));
    // nnnnnnXXXnnn
    int hundredThousands = Integer.parseInt(snumber.substring(6,9));
    // nnnnnnnnnXXX
    int thousands = Integer.parseInt(snumber.substring(9,12));

    String tradBillions;
    switch (billions) {
    case 0:
      tradBillions = "";
      break;
    case 1 :
      tradBillions = convertLessThanOneThousand(billions)
      + " billion ";
      break;
    default :
      tradBillions = convertLessThanOneThousand(billions)
      + " billion ";
    }
    String result =  tradBillions;

    String tradMillions;
    switch (millions) {
    case 0:
      tradMillions = "";
      break;
    case 1 :
      tradMillions = convertLessThanOneThousand(millions)
         + " million ";
      break;
    default :
      tradMillions = convertLessThanOneThousand(millions)
         + " million ";
    }
    result =  result + tradMillions;

    String tradHundredThousands;
    switch (hundredThousands) {
    case 0:
      tradHundredThousands = "";
      break;
    case 1 :
      tradHundredThousands = "one thousand ";
      break;
    default :
      tradHundredThousands = convertLessThanOneThousand(hundredThousands)
         + " thousand ";
    }
    result =  result + tradHundredThousands;

    String tradThousand;
    tradThousand = convertLessThanOneThousand(thousands);
    result =  result + tradThousand;

    // remove extra spaces!
    return result.replaceAll("^\\s+", "").replaceAll("\\b\\s{2,}\\b", " ");
  }

  /**
   * testing
   * @param args
   */
  public static void main(String[] args) {
    System.out.println("*** " + EnglishNumberToWords.convert(0));
    System.out.println("*** " + EnglishNumberToWords.convert(1));
    System.out.println("*** " + EnglishNumberToWords.convert(16));
    System.out.println("*** " + EnglishNumberToWords.convert(100));
    System.out.println("*** " + EnglishNumberToWords.convert(118));
    System.out.println("*** " + EnglishNumberToWords.convert(200));
    System.out.println("*** " + EnglishNumberToWords.convert(219));
    System.out.println("*** " + EnglishNumberToWords.convert(800));
    System.out.println("*** " + EnglishNumberToWords.convert(801));
    System.out.println("*** " + EnglishNumberToWords.convert(1316));
    System.out.println("*** " + EnglishNumberToWords.convert(1000000));
    System.out.println("*** " + EnglishNumberToWords.convert(2000000));
    System.out.println("*** " + EnglishNumberToWords.convert(3000200));
    System.out.println("*** " + EnglishNumberToWords.convert(700000));
    System.out.println("*** " + EnglishNumberToWords.convert(9000000));
    System.out.println("*** " + EnglishNumberToWords.convert(9001000));
    System.out.println("*** " + EnglishNumberToWords.convert(123456789));
    System.out.println("*** " + EnglishNumberToWords.convert(2147483647));
    System.out.println("*** " + EnglishNumberToWords.convert(3000000010L));

    /*
     *** zero
     *** one
     *** sixteen
     *** one hundred
     *** one hundred eighteen
     *** two hundred
     *** two hundred nineteen
     *** eight hundred
     *** eight hundred one
     *** one thousand three hundred sixteen
     *** one million
     *** two millions
     *** three millions two hundred
     *** seven hundred thousand
     *** nine millions
     *** nine millions one thousand
     *** one hundred twenty three millions four hundred
     **      fifty six thousand seven hundred eighty nine
     *** two billion one hundred forty seven millions
     **      four hundred eighty three thousand six hundred forty seven
     *** three billion ten
     **/
  }
}

Français Quite different than the english version but french is a lot more difficult!

package com.rgagnon.howto;

import java.text.*;

class FrenchNumberToWords {
  private static final String[] dizaineNames = {
    "",
    "",
    "vingt",
    "trente",
    "quarante",
    "cinquante",
    "soixante",
    "soixante",
    "quatre-vingt",
    "quatre-vingt"
  };

  private static final String[] uniteNames1 = {
    "",
    "un",
    "deux",
    "trois",
    "quatre",
    "cinq",
    "six",
    "sept",
    "huit",
    "neuf",
    "dix",
    "onze",
    "douze",
    "treize",
    "quatorze",
    "quinze",
    "seize",
    "dix-sept",
    "dix-huit",
    "dix-neuf"
  };

  private static final String[] uniteNames2 = {
    "",
    "",
    "deux",
    "trois",
    "quatre",
    "cinq",
    "six",
    "sept",
    "huit",
    "neuf",
    "dix"
  };

  private FrenchNumberToWords() {}

  private static String convertZeroToHundred(int number) {

    int laDizaine = number / 10;
    int lUnite = number % 10;
    String resultat = "";

    switch (laDizaine) {
    case 1 :
    case 7 :
    case 9 :
      lUnite = lUnite + 10;
      break;
    default:
    }

    // séparateur "-" "et"  ""
    String laLiaison = "";
    if (laDizaine > 1) {
      laLiaison = "-";
    }
    // cas particuliers
    switch (lUnite) {
    case 0:
      laLiaison = "";
      break;
    case 1 :
      if (laDizaine == 8) {
        laLiaison = "-";
      }
      else {
        laLiaison = " et ";
      }
      break;
    case 11 :
      if (laDizaine==7) {
        laLiaison = " et ";
      }
      break;
    default:
    }

    // dizaines en lettres
    switch (laDizaine) {
    case 0:
      resultat = uniteNames1[lUnite];
      break;
    case 8 :
      if (lUnite == 0) {
        resultat = dizaineNames[laDizaine];
      }
      else {
        resultat = dizaineNames[laDizaine]
                                + laLiaison + uniteNames1[lUnite];
      }
      break;
    default :
      resultat = dizaineNames[laDizaine]
                              + laLiaison + uniteNames1[lUnite];
    }
    return resultat;
  }

  private static String convertLessThanOneThousand(int number) {

    int lesCentaines = number / 100;
    int leReste = number % 100;
    String sReste = convertZeroToHundred(leReste);

    String resultat;
    switch (lesCentaines) {
    case 0:
      resultat = sReste;
      break;
    case 1 :
      if (leReste > 0) {
        resultat = "cent " + sReste;
      }
      else {
        resultat = "cent";
      }
      break;
    default :
      if (leReste > 0) {
        resultat = uniteNames2[lesCentaines] + " cent " + sReste;
      }
      else {
        resultat = uniteNames2[lesCentaines] + " cents";
      }
    }
    return resultat;
  }

  public static String convert(long number) {
    // 0 à 999 999 999 999
    if (number == 0) { return "zéro"; }

    String snumber = Long.toString(number);

    // pad des "0"
    String mask = "000000000000";
    DecimalFormat df = new DecimalFormat(mask);
    snumber = df.format(number);

    // XXXnnnnnnnnn
    int lesMilliards = Integer.parseInt(snumber.substring(0,3));
    // nnnXXXnnnnnn
    int lesMillions  = Integer.parseInt(snumber.substring(3,6));
    // nnnnnnXXXnnn
    int lesCentMille = Integer.parseInt(snumber.substring(6,9));
    // nnnnnnnnnXXX
    int lesMille = Integer.parseInt(snumber.substring(9,12));

    String tradMilliards;
    switch (lesMilliards) {
    case 0:
      tradMilliards = "";
      break;
    case 1 :
      tradMilliards = convertLessThanOneThousand(lesMilliards)
         + " milliard ";
      break;
    default :
      tradMilliards = convertLessThanOneThousand(lesMilliards)
         + " milliards ";
    }
    String resultat =  tradMilliards;

    String tradMillions;
    switch (lesMillions) {
    case 0:
      tradMillions = "";
      break;
    case 1 :
      tradMillions = convertLessThanOneThousand(lesMillions)
         + " million ";
      break;
    default :
      tradMillions = convertLessThanOneThousand(lesMillions)
         + " millions ";
    }
    resultat =  resultat + tradMillions;

    String tradCentMille;
    switch (lesCentMille) {
    case 0:
      tradCentMille = "";
      break;
    case 1 :
      tradCentMille = "mille ";
      break;
    default :
      tradCentMille = convertLessThanOneThousand(lesCentMille)
         + " mille ";
    }
    resultat =  resultat + tradCentMille;

    String tradMille;
    tradMille = convertLessThanOneThousand(lesMille);
    resultat =  resultat + tradMille;

    return resultat;
  }

  public static void main(String[] args) {
    System.out.println("*** " + FrenchNumberToWords.convert(0));
    System.out.println("*** " + FrenchNumberToWords.convert(9));
    System.out.println("*** " + FrenchNumberToWords.convert(19));
    System.out.println("*** " + FrenchNumberToWords.convert(21));
    System.out.println("*** " + FrenchNumberToWords.convert(28));
    System.out.println("*** " + FrenchNumberToWords.convert(71));
    System.out.println("*** " + FrenchNumberToWords.convert(72));
    System.out.println("*** " + FrenchNumberToWords.convert(80));
    System.out.println("*** " + FrenchNumberToWords.convert(81));
    System.out.println("*** " + FrenchNumberToWords.convert(89));
    System.out.println("*** " + FrenchNumberToWords.convert(90));
    System.out.println("*** " + FrenchNumberToWords.convert(91));
    System.out.println("*** " + FrenchNumberToWords.convert(97));
    System.out.println("*** " + FrenchNumberToWords.convert(100));
    System.out.println("*** " + FrenchNumberToWords.convert(101));
    System.out.println("*** " + FrenchNumberToWords.convert(110));
    System.out.println("*** " + FrenchNumberToWords.convert(120));
    System.out.println("*** " + FrenchNumberToWords.convert(200));
    System.out.println("*** " + FrenchNumberToWords.convert(201));
    System.out.println("*** " + FrenchNumberToWords.convert(232));
    System.out.println("*** " + FrenchNumberToWords.convert(999));
    System.out.println("*** " + FrenchNumberToWords.convert(1000));
    System.out.println("*** " + FrenchNumberToWords.convert(1001));
    System.out.println("*** " + FrenchNumberToWords.convert(10000));
    System.out.println("*** " + FrenchNumberToWords.convert(10001));
    System.out.println("*** " + FrenchNumberToWords.convert(100000));
    System.out.println("*** " + FrenchNumberToWords.convert(2000000));
    System.out.println("*** " + FrenchNumberToWords.convert(3000000000L));
    System.out.println("*** " + FrenchNumberToWords.convert(2147483647));
    /*
     *** OUTPUT
     *** zéro
     *** neuf
     *** dix-neuf
     *** vingt et un
     *** vingt-huit
     *** soixante et onze
     *** soixante-douze
     *** quatre-vingt
     *** quatre-vingt-un
     *** quatre-vingt-neuf
     *** quatre-vingt-dix
     *** quatre-vingt-onze
     *** quatre-vingt-dix-sept
     *** cent
     *** cent un
     *** cent dix
     *** cent vingt
     *** deux cents
     *** deux cent un
     *** deux cent trente-deux
     *** neuf cent quatre-vingt-dix-neuf
     *** mille
     *** mille un
     *** dix mille
     *** dix mille un
     *** cent mille
     *** deux millions
     *** trois milliards
     *** deux milliards cent quarante-sept millions
     **          quatre cent quatre-vingt-trois mille six cent quarante-sept
     */
  }
}

You can handle "dollar and cent" conversion by calling the "convert" method two times.

String phrase = "12345.67" ;
Float num = new Float( phrase ) ;
int dollars = (int)Math.floor( num ) ;
int cent = (int)Math.floor( ( num - dollars ) * 100.0f ) ;

String s = "$ " + EnglishNumberToWords.convert( dollars ) + " and "
           + EnglishNumberToWords.convert( cent ) + " cents" ;

Another way to use a built-in function of your DBMS (if available). For Oracle

SQL> select to_char(to_date(873,'J'), 'JSP') as converted_form from dual;

CONVERTED_FORM
---------------------------
EIGHT HUNDRED SEVENTY-THREE

SQL>
'JSP' means :
J : the Julian format.
SP : spells the word for the number passed to to_date

Solution 2

ICU4J contains nice number-spellout support. The files with the "rules" can be easily edited, and it's no problem to add other languages (we did it e.g. for Polish and Russian).

Solution 3

Because you cannot have a general algorithm for every locale, no. You have to implement your own algorithm for every locale that you are supporting.

** EDIT **

Just for the heck of it, I played around until I got this class. It cannot display Long.MIN_VALUE because of bit restrictions... but I presume it could be modified and change long value types to double for decimal or even bigger numbers It can display any numbers up to 66 digits and 26 decimals using a string representation of the number. You may add more ScaleUnit for more decimals...

/**
 * This class will convert numeric values into an english representation
 * 
 * For units, see : http://www.jimloy.com/math/billion.htm
 * 
 * @author [email protected]
 */
public class NumberToWords {

    static public class ScaleUnit {
        private int exponent;
        private String[] names;
        private ScaleUnit(int exponent, String...names) {
            this.exponent = exponent;
            this.names = names;
        }
        public int getExponent() {
            return exponent;
        }
        public String getName(int index) {
            return names[index];
        }
    }

    /**
     * See http://www.wordiq.com/definition/Names_of_large_numbers
     */
    static private ScaleUnit[] SCALE_UNITS = new ScaleUnit[] {
        new ScaleUnit(63, "vigintillion", "decilliard"),
        new ScaleUnit(60, "novemdecillion", "decillion"),
        new ScaleUnit(57, "octodecillion", "nonilliard"),
        new ScaleUnit(54, "septendecillion", "nonillion"),
        new ScaleUnit(51, "sexdecillion", "octilliard"),
        new ScaleUnit(48, "quindecillion", "octillion"),
        new ScaleUnit(45, "quattuordecillion", "septilliard"),
        new ScaleUnit(42, "tredecillion", "septillion"),
        new ScaleUnit(39, "duodecillion", "sextilliard"),
        new ScaleUnit(36, "undecillion", "sextillion"),
        new ScaleUnit(33, "decillion", "quintilliard"),
        new ScaleUnit(30, "nonillion", "quintillion"),
        new ScaleUnit(27, "octillion", "quadrilliard"),
        new ScaleUnit(24, "septillion", "quadrillion"),
        new ScaleUnit(21, "sextillion", "trilliard"),
        new ScaleUnit(18, "quintillion", "trillion"),
        new ScaleUnit(15, "quadrillion", "billiard"),
        new ScaleUnit(12, "trillion", "billion"),
        new ScaleUnit(9, "billion", "milliard"),
        new ScaleUnit(6, "million", "million"),
        new ScaleUnit(3, "thousand", "thousand"),
        new ScaleUnit(2, "hundred", "hundred"),
        //new ScaleUnit(1, "ten", "ten"),
        //new ScaleUnit(0, "one", "one"),
        new ScaleUnit(-1, "tenth", "tenth"),
        new ScaleUnit(-2, "hundredth", "hundredth"),
        new ScaleUnit(-3, "thousandth", "thousandth"),
        new ScaleUnit(-4, "ten-thousandth", "ten-thousandth"),
        new ScaleUnit(-5, "hundred-thousandth", "hundred-thousandth"),
        new ScaleUnit(-6, "millionth", "millionth"),
        new ScaleUnit(-7, "ten-millionth", "ten-millionth"),
        new ScaleUnit(-8, "hundred-millionth", "hundred-millionth"),
        new ScaleUnit(-9, "billionth", "milliardth"),
        new ScaleUnit(-10, "ten-billionth", "ten-milliardth"),
        new ScaleUnit(-11, "hundred-billionth", "hundred-milliardth"),
        new ScaleUnit(-12, "trillionth", "billionth"),
        new ScaleUnit(-13, "ten-trillionth", "ten-billionth"),
        new ScaleUnit(-14, "hundred-trillionth", "hundred-billionth"),
        new ScaleUnit(-15, "quadrillionth", "billiardth"),
        new ScaleUnit(-16, "ten-quadrillionth", "ten-billiardth"),
        new ScaleUnit(-17, "hundred-quadrillionth", "hundred-billiardth"),
        new ScaleUnit(-18, "quintillionth", "trillionth"),
        new ScaleUnit(-19, "ten-quintillionth", "ten-trillionth"),
        new ScaleUnit(-20, "hundred-quintillionth", "hundred-trillionth"),
        new ScaleUnit(-21, "sextillionth", "trilliardth"),
        new ScaleUnit(-22, "ten-sextillionth", "ten-trilliardth"),
        new ScaleUnit(-23, "hundred-sextillionth", "hundred-trilliardth"),
        new ScaleUnit(-24, "septillionth","quadrillionth"),
        new ScaleUnit(-25, "ten-septillionth","ten-quadrillionth"),
        new ScaleUnit(-26, "hundred-septillionth","hundred-quadrillionth"),
    };

    static public enum Scale {
        SHORT,
        LONG;

        public String getName(int exponent) {
            for (ScaleUnit unit : SCALE_UNITS) {
                if (unit.getExponent() == exponent) {
                    return unit.getName(this.ordinal());
                }
            }
            return ""; 
        }
    }

    /**
     * Change this scale to support American and modern British value (short scale)
     * or Traditional British value (long scale)
     */
    static public Scale SCALE = Scale.SHORT; 


    static abstract public class AbstractProcessor {

        static protected final String SEPARATOR = " ";
        static protected final int NO_VALUE = -1;

        protected List<Integer> getDigits(long value) {
            ArrayList<Integer> digits = new ArrayList<Integer>();
            if (value == 0) {
                digits.add(0);
            } else {
                while (value > 0) {
                    digits.add(0, (int) value % 10);
                    value /= 10;
                }
            }
            return digits;
        }

        public String getName(long value) {
            return getName(Long.toString(value));
        }

        public String getName(double value) {
            return getName(Double.toString(value));
        }

        abstract public String getName(String value);
    }

    static public class UnitProcessor extends AbstractProcessor {

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

        @Override
        public String getName(String value) {
            StringBuilder buffer = new StringBuilder();

            int offset = NO_VALUE;
            int number;
            if (value.length() > 3) {
                number = Integer.valueOf(value.substring(value.length() - 3), 10);
            } else {
                number = Integer.valueOf(value, 10);
            }
            number %= 100;
            if (number < 10) {
                offset = (number % 10) - 1;
                //number /= 10;
            } else if (number < 20) {
                offset = (number % 20) - 1;
                //number /= 100;
            }

            if (offset != NO_VALUE && offset < TOKENS.length) {
                buffer.append(TOKENS[offset]);
            }

            return buffer.toString();
        }

    }

    static public class TensProcessor extends AbstractProcessor {

        static private final String[] TOKENS = new String[] {
            "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
        };

        static private final String UNION_SEPARATOR = "-";

        private UnitProcessor unitProcessor = new UnitProcessor();

        @Override
        public String getName(String value) {
            StringBuilder buffer = new StringBuilder();
            boolean tensFound = false;

            int number;
            if (value.length() > 3) {
                number = Integer.valueOf(value.substring(value.length() - 3), 10);
            } else {
                number = Integer.valueOf(value, 10);
            }
            number %= 100;   // keep only two digits
            if (number >= 20) {
                buffer.append(TOKENS[(number / 10) - 2]);
                number %= 10;
                tensFound = true;
            } else {
                number %= 20;
            }

            if (number != 0) {
                if (tensFound) {
                    buffer.append(UNION_SEPARATOR);
                }
                buffer.append(unitProcessor.getName(number));
            }

            return buffer.toString();
        }
    }

    static public class HundredProcessor extends AbstractProcessor {

        private int EXPONENT = 2;

        private UnitProcessor unitProcessor = new UnitProcessor();
        private TensProcessor tensProcessor = new TensProcessor();

        @Override
        public String getName(String value) {
            StringBuilder buffer = new StringBuilder();

            int number;
            if (value.isEmpty()) {
                number = 0;
            } else if (value.length() > 4) {
                number = Integer.valueOf(value.substring(value.length() - 4), 10);
            } else {
                number = Integer.valueOf(value, 10);
            }
            number %= 1000;  // keep at least three digits

            if (number >= 100) {
                buffer.append(unitProcessor.getName(number / 100));
                buffer.append(SEPARATOR);
                buffer.append(SCALE.getName(EXPONENT));
            }

            String tensName = tensProcessor.getName(number % 100);

            if (!tensName.isEmpty() && (number >= 100)) {
                buffer.append(SEPARATOR);
            }
            buffer.append(tensName);

            return buffer.toString();
        }
    }

    static public class CompositeBigProcessor extends AbstractProcessor {

        private HundredProcessor hundredProcessor = new HundredProcessor();
        private AbstractProcessor lowProcessor;
        private int exponent;

        public CompositeBigProcessor(int exponent) {
            if (exponent <= 3) {
                lowProcessor = hundredProcessor;
            } else {
                lowProcessor = new CompositeBigProcessor(exponent - 3);
            }
            this.exponent = exponent;
        }

        public String getToken() {
            return SCALE.getName(getPartDivider());
        }

        protected AbstractProcessor getHighProcessor() {
            return hundredProcessor;
        }

        protected AbstractProcessor getLowProcessor() {
            return lowProcessor;
        }

        public int getPartDivider() {
            return exponent;
        }

        @Override
        public String getName(String value) {
            StringBuilder buffer = new StringBuilder();

            String high, low;
            if (value.length() < getPartDivider()) {
                high = "";
                low = value;
            } else {
                int index = value.length() - getPartDivider();
                high = value.substring(0, index);
                low = value.substring(index);
            }

            String highName = getHighProcessor().getName(high);
            String lowName = getLowProcessor().getName(low);

            if (!highName.isEmpty()) {
                buffer.append(highName);
                buffer.append(SEPARATOR);
                buffer.append(getToken());

                if (!lowName.isEmpty()) {
                    buffer.append(SEPARATOR);
                }
            }

            if (!lowName.isEmpty()) {
                buffer.append(lowName);
            }

            return buffer.toString();
        }
    }

    static public class DefaultProcessor extends AbstractProcessor {

        static private String MINUS = "minus";
        static private String UNION_AND = "and";

        static private String ZERO_TOKEN = "zero";

        private AbstractProcessor processor = new CompositeBigProcessor(63);

        @Override
        public String getName(String value) {
            boolean negative = false;
            if (value.startsWith("-")) {
                negative = true;
                value = value.substring(1);
            }

            int decimals = value.indexOf(".");
            String decimalValue = null;
            if (0 <= decimals) {
                decimalValue = value.substring(decimals + 1);
                value = value.substring(0, decimals);
            }

            String name = processor.getName(value);

            if (name.isEmpty()) {
                name = ZERO_TOKEN;
            } else if (negative) {
                name = MINUS.concat(SEPARATOR).concat(name); 
            }

            if (!(null == decimalValue || decimalValue.isEmpty())) {
                name = name.concat(SEPARATOR).concat(UNION_AND).concat(SEPARATOR)
                    .concat(processor.getName(decimalValue))
                    .concat(SEPARATOR).concat(SCALE.getName(-decimalValue.length()));
            }

            return name;
        }

    }

    static public AbstractProcessor processor;


    public static void main(String...args) {

        processor = new DefaultProcessor();

        long[] values = new long[] {
            0,
            4,
            10,
            12,
            100,
            108,
            299,
            1000,
            1003,
            2040,
            45213,
            100000,
            100005,
            100010,
            202020,
            202022,
            999999,
            1000000,
            1000001,
            10000000,
            10000007,
            99999999,
            Long.MAX_VALUE,
            Long.MIN_VALUE
        };

        String[] strValues = new String[] {
            "0001.2",
            "3.141592"
        };

        for (long val : values) {
            System.out.println(val + " = " + processor.getName(val) );
        }

        for (String strVal : strValues) {
            System.out.println(strVal + " = " + processor.getName(strVal) );
        }

        // generate a very big number...
        StringBuilder bigNumber = new StringBuilder();
        for (int d=0; d<66; d++) {
            bigNumber.append( (char) ((Math.random() * 10) + '0'));
        }
        bigNumber.append(".");
        for (int d=0; d<26; d++) {
            bigNumber.append( (char) ((Math.random() * 10) + '0'));
        }

        System.out.println(bigNumber.toString() + " = " + processor.getName(bigNumber.toString()));

    }

}

and a sample output (for the random big number generator)

0 = zero
4 = four
10 = ten
12 = twelve
100 = one hundred
108 = one hundred eight
299 = two hundred ninety-nine
1000 = one thousand
1003 = one thousand three
2040 = two thousand fourty
45213 = fourty-five thousand two hundred thirteen
100000 = one hundred thousand
100005 = one hundred thousand five
100010 = one hundred thousand ten
202020 = two hundred two thousand twenty
202022 = two hundred two thousand twenty-two
999999 = nine hundred ninety-nine thousand nine hundred ninety-nine
1000000 = one million
1000001 = one million one
10000000 = ten million
10000007 = ten million seven
99999999 = ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine
9223372036854775807 = nine quintillion two hundred twenty-three quadrillion three hundred seventy-two trillion thirty-six billion eight hundred fifty-four million seven hundred seventy-five thousand eight hundred seven
-9223372036854775808 = minus nine quintillion two hundred twenty-three quadrillion three hundred seventy-two trillion thirty-six billion eight hundred fifty-four million seven hundred seventy-five thousand eight hundred eight
0001.2 = one and two tenth
3.141592 = three and one hundred fourty-one thousand five hundred ninety-two millionth
694780458103427072928672912656674465845126458162617425283733729646.85695031739734695391404376 = six hundred ninety-four vigintillion seven hundred eighty novemdecillion four hundred fifty-eight octodecillion one hundred three septendecillion four hundred twenty-seven sexdecillion seventy-two quindecillion nine hundred twenty-eight quattuordecillion six hundred seventy-two tredecillion nine hundred twelve duodecillion six hundred fifty-six undecillion six hundred seventy-four decillion four hundred sixty-five nonillion eight hundred fourty-five octillion one hundred twenty-six septillion four hundred fifty-eight sextillion one hundred sixty-two quintillion six hundred seventeen quadrillion four hundred twenty-five trillion two hundred eighty-three billion seven hundred thirty-three million seven hundred twenty-nine thousand six hundred fourty-six and eighty-five septillion six hundred ninety-five sextillion thirty-one quintillion seven hundred thirty-nine quadrillion seven hundred thirty-four trillion six hundred ninety-five billion three hundred ninety-one million four hundred four thousand three hundred seventy-six hundred-septillionth

Solution 4

I think that this solution is not the best, since it works only for int, but i think it's great for a beginner.

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

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

    public static String convert(final int n) {
        if (n < 0) {
            return "minus " + convert(-n);
        }

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

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

        if (n < 1000) {
            return units[n / 100] + " hundred" + ((n % 100 != 0) ? " " : "") + convert(n % 100);
        }

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

        if (n < 1000000000) {
            return convert(n / 1000000) + " million" + ((n % 1000000 != 0) ? " " : "") + convert(n % 1000000);
        }

        return convert(n / 1000000000) + " billion"  + ((n % 1000000000 != 0) ? " " : "") + convert(n % 1000000000);
    }

    public static void main(final String[] args) {
        final Random generator = new Random();

        int n;
        for (int i = 0; i < 20; i++) {
            n = generator.nextInt(Integer.MAX_VALUE);

            System.out.printf("%10d = '%s'%n", n, convert(n));
        }

        n = 1000;
        System.out.printf("%10d = '%s'%n", n, convert(n));

        n = 2000;
        System.out.printf("%10d = '%s'%n", n, convert(n));

        n = 10000;
        System.out.printf("%10d = '%s'%n", n, convert(n));

        n = 11000;
        System.out.printf("%10d = '%s'%n", n, convert(n));

        n = 999999999;
        System.out.printf("%10d = '%s'%n", n, convert(n));

        n = Integer.MAX_VALUE;
        System.out.printf("%10d = '%s'%n", n, convert(n));
    }
}

The test creates 20 random numbers up to Integer.MAX_VALUE and than some that know to be problematic, because of 0, 10, etc.. Output:

   5599908 = 'five million five hundred ninety nine thousand nine hundred eight'
 192603486 = 'one hundred ninety two million six hundred three thousand four hundred eighty six'
1392431868 = 'one billion three hundred ninety two million four hundred thirty one thousand eight hundred sixty eight'
1023787010 = 'one billion twenty three million seven hundred eighty seven thousand ten'
1364396236 = 'one billion three hundred sixty four million three hundred ninety six thousand two hundred thirty six'
1511255671 = 'one billion five hundred eleven million two hundred fifty five thousand six hundred seventy one'
 225955221 = 'two hundred twenty five million nine hundred fifty five thousand two hundred twenty one'
1890141052 = 'one billion eight hundred ninety million one hundred forty one thousand fifty two'
 261839422 = 'two hundred sixty one million eight hundred thirty nine thousand four hundred twenty two'
 728428650 = 'seven hundred twenty eight million four hundred twenty eight thousand six hundred fifty'
 860607319 = 'eight hundred sixty million six hundred seven thousand three hundred nineteen'
 719753587 = 'seven hundred nineteen million seven hundred fifty three thousand five hundred eighty seven'
2063829124 = 'two billion sixty three million eight hundred twenty nine thousand one hundred twenty four'
1081010996 = 'one billion eighty one million ten thousand nine hundred ninety six'
 999215799 = 'nine hundred ninety nine million two hundred fifteen thousand seven hundred ninety nine'
2105226236 = 'two billion one hundred five million two hundred twenty six thousand two hundred thirty six'
1431882940 = 'one billion four hundred thirty one million eight hundred eighty two thousand nine hundred forty'
1991707241 = 'one billion nine hundred ninety one million seven hundred seven thousand two hundred forty one'
1088301563 = 'one billion eighty eight million three hundred one thousand five hundred sixty three'
 964601609 = 'nine hundred sixty four million six hundred one thousand six hundred nine'
      1000 = 'one thousand'
      2000 = 'two thousand'
     10000 = 'ten thousand'
     11000 = 'eleven thousand'
 999999999 = 'nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine'
2147483647 = 'two billion one hundred forty seven million four hundred eighty three thousand six hundred forty seven'

Hope it helps :)

Solution 5

package it.tommasoresti.facebook;

class NumbersToWords {

    private static final String ZERO = "zero";
    private static String[] oneToNine = {
            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"
    };

    private static String[] tenToNinteen = {
            "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
    };

    private static String[] dozens = {
            "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
    };

    public static String solution(int number) {
        if(number == 0)
            return ZERO;

        return generate(number).trim();
    }

    public static String generate(int number) {
        if(number >= 1000000000) {
            return generate(number / 1000000000) + " billion " + generate(number % 1000000000);
        }
        else if(number >= 1000000) {
            return generate(number / 1000000) + " million " + generate(number % 1000000);
        }
        else if(number >= 1000) {
            return generate(number / 1000) + " thousand " + generate(number % 1000);
        }
        else if(number >= 100) {
            return generate(number / 100) + " hundred " + generate(number % 100);
        }

        return generate1To99(number);
    }

    private static String generate1To99(int number) {
        if (number == 0)
            return "";

        if (number <= 9)
            return oneToNine[number - 1];
        else if (number <= 19)
            return tenToNinteen[number % 10];
        else {
            return dozens[number / 10 - 1] + " " + generate1To99(number % 10);
        }
    }
}

Test

@Test
public void given_a_complex_number() throws Exception {
    assertThat(solution(1234567890),
        is("one billion two hundred thirty four million five hundred sixty seven thousand eight hundred ninety"));
}
Share:
379,815
Jason
Author by

Jason

Updated on July 08, 2022

Comments

  • Jason
    Jason almost 2 years

    We currently have a crude mechanism to convert numbers to words (e.g. using a few static arrays) and based on the size of the number translating that into an english text. But we are running into issues for numbers which are huge.

    10183 = Ten thousand one hundred eighty three
    90 = Ninety
    5888 = Five thousand eight hundred eighty eight
    

    Is there an easy to use function in any of the math libraries which I can use for this purpose?

  • Jason
    Jason over 13 years
    just need this for english alone
  • Yanick Rochon
    Yanick Rochon over 13 years
    @Jason, I was answering the question "Is there an easy to use function in any of the math libraries which I can use for this purpose?"
  • Steven R. Loomis
    Steven R. Loomis over 13 years
    ICU4J's data comes from CLDR unicode.org/cldr and already supports Polish and Russian. unicode.org/repos/cldr/trunk/common/rbnf Did you file a ticket if you found issues with the existing rules?
  • Landei
    Landei over 13 years
    No, but we did this some years ago, and if I remember right, we needed some additional things. But good to know!
  • Steven R. Loomis
    Steven R. Loomis over 13 years
    RBNF has had major overhauls a year or so ago, both in CLDR and ICU. Check it out.
  • marcolopes
    marcolopes about 13 years
    Limited method: it does not convert large numbers neither supports decimal numbers.
  • Don Roby
    Don Roby almost 13 years
    American English or British English? Billion has different meanings between these cultures.
  • Stephen C
    Stephen C almost 13 years
    @Don Roby - AFAIK, that is a historical concern only. Most british folks use the american english meaning these days. ( Of course, there are a few eccentrics around who write letters (in green ink) to The Times about this kind of thing, but they probably won't notice, on account of refusing to learn to use computers :-) )
  • Sandip Armal Patil
    Sandip Armal Patil over 11 years
    You need to add some description along with code... Welcome to Stackoverflow
  • CoperNick
    CoperNick over 11 years
    Lakh and Crore is used Indian English but not in Europe and not in America. See Wikipedia.
  • Abhishek Chatterjee
    Abhishek Chatterjee over 10 years
    @Rochon : Nice code !! Helped me a lot..but has a small bug..test with "10.00"...to remove this bug a want to add a little fix while converting string to word, int indexOfDecimal = value.indexOf("."); String decimal = value.substring(indexOfDecimal + 1, value.length()); BigDecimal decimalValue = new BigDecimal(decimal); if (decimalValue.compareTo(BigDecimal.ZERO) == 0) value = value.substring(0, indexOfDecimal);
  • Yanick Rochon
    Yanick Rochon over 10 years
    @AbhishekChatterjee, thanks! The idea of "good code" and "best practices" are to avoid putting redundant and unnecessary checks where they don't belong (to avoid code complexity); therefore providing the correct value should not be the concern of a class (or method) that format said value (format != validation). Moreover, the method getName(string) is a convenient way to provide a number that is otherwise too big to be passed directly by value (ie. using a double). The example does not provide invalid output as it is assumed that the values have properly been validated.
  • Yanick Rochon
    Yanick Rochon over 10 years
    @AbhishekChatterjee, I should have perhaps changed the method signature to provide with BigInteger and BigDecimal instead. That would've avoided the problem you are describing.
  • Taryn
    Taryn over 10 years
    While this answer is over 3 years old, it would be helpful if you could include essential parts of the link here in the event that link ever fails to be available.
  • Pang
    Pang about 10 years
    "Despite being related to the word "four" (4), 40 is spelled "forty", and not "fourty"." - Wikipedia
  • ooxi
    ooxi almost 10 years
    This should be the selected answer since the others depend on bug ridden and unlocalized example implementations
  • nobody
    nobody almost 10 years
    This code has a bug. You've spelled 90 as "ninty" in one location and "ninety" in another.
  • Muthu Ganapathy Nathan
    Muthu Ganapathy Nathan about 9 years
    Yes! This should be an selected answer... It worked like a charm... It translates to any language, any region, any country as listed here iana.org/assignments/language-subtag-registry/….. The usage is as simple as. RuleBasedNumberFormat ruleBasedNumberFormat = new RuleBasedNumberFormat( new Locale("EN", "US"), RuleBasedNumberFormat.SPELLOUT ); System.out.println(ruleBasedNumberFormat.format(value));
  • Justin
    Justin almost 9 years
    FYI, this link seems to be broken
  • weston
    weston over 8 years
    Is there a reason why all these answers have bad grammar? "one thousand two hundred thirty-four" should be "one thousand, two hundred and thirty-four". Is this some banking English I don't know about?
  • sensei
    sensei over 7 years
    I've taken your code for the french version and ported it to groovy while making it work for bigger numbers. It's pretty easy to make it work with even bigger ones. In case someone's interested, it's here. Thanks for the base material !
  • 4castle
    4castle about 7 years
    @weston In American English the "and" is not used. That's only in British English.
  • weston
    weston about 7 years
    @4castle heh, American wife, I live in Canada and I never noticed!
  • adesh singh
    adesh singh about 7 years
    Program gives wrong output when you enter 100500 but in rest cases works fine
  • jmj
    jmj about 7 years
    @adeshsingh while you are right there. could you fix the code and update the answer. this was ~7 year old code
  • Sebastian Cardona Osorio
    Sebastian Cardona Osorio over 5 years
    For spanish speakers I suggesting read this answer too: stackoverflow.com/a/10019105/3954514
  • Bu Saeed
    Bu Saeed over 4 years
    Can anybody update this code to convert decimal numbers also?
  • Mohamed Nageh
    Mohamed Nageh over 4 years
    brilliant solution.
  • JuanMoreno
    JuanMoreno about 4 years
    You can also use ICUJ, I put an example here gist.github.com/earth001/bf30be16489e1c2538ac3dd55d9ffc94
  • Anand
    Anand almost 4 years
    I have developed a REST Api to cater Number to Words for any language. Free to Use, try it out 49.206.25.208:18080/api/v1/generate/…
  • Tirth Timaniya
    Tirth Timaniya over 3 years
    Great Work bro!!. but there is one bug in your code. if you type 10014 then it will print ten thousand hundred fourteen.. you just need to check if(temp%10 == 0) { wordList.addFirst(numberMap.getOrDefault(temp%10,"")); } else { wordList.addFirst("hundred"); wordList.addFirst(numberMap.getOrDefault(temp%10,"")); } It will fix this bug..
  • Sambhav Khandelwal
    Sambhav Khandelwal about 2 years
    Its way too good but what about for Indian number? We don't have millions and etc...