Friday, July 18, 2014

Generate english phrase that describes a integer

Problem

Given an integer between 0 and 999,999, print an English phrase that describes the integer (e.g., “One Thousand, Two Hundred and Thirty Four”).
Solution


private static final Map<Integer, String> digitsToStrings;
static {
    Map<Integer, String> aMap = new HashMap<Integer, String>();
 
    aMap.put(1, "One");
    aMap.put(2, "Two");
    aMap.put(3, "Three");
    aMap.put(4, "Four");
    aMap.put(5, "Five");
    aMap.put(6, "Six");
    aMap.put(7, "Seven");
    aMap.put(8, "Eight");
    aMap.put(9, "Nine");
 
    aMap.put(10, "Ten");
    aMap.put(11, "Eleven");
    aMap.put(12, "Twelve");
    aMap.put(13, "Thirteen");
    aMap.put(14, "Fourteen");
    aMap.put(15, "Fivteen");
    aMap.put(16, "Sixteen");
    aMap.put(17, "Seventeen");
    aMap.put(18, "Eighteen");
    aMap.put(19, "Nineteen");
 
    aMap.put(20, "Twenty");
    aMap.put(30, "Thirty");
    aMap.put(40, "Forty");
    aMap.put(50, "Fifty");
    aMap.put(60, "Sixty");
    aMap.put(70, "Seventy");
    aMap.put(80, "Eighty");
    aMap.put(90, "Ninety");
 
    digitsToStrings = Collections.unmodifiableMap(aMap);
}
 
// number is between 0 to 999
private static String hundredToString(int number) {
    String result = new String();
    int numberOfHandred = number / 100;
    result += numberOfHandred == 0 ? "" : digitsToStrings
            .get(numberOfHandred) + " Hundred";
    int residual = number - numberOfHandred * 100;
    if (residual == 0)
        return result;
    else if (numberOfHandred != 0)
        result += " and ";
    int numberOfTens = residual / 10;
 
    switch (numberOfTens) {
    case 0: {
        result += "";
        break;
    }
    case 1: {
        result += digitsToStrings.get(residual);
        return result;
    }
    default: {
        result += numberOfTens == 0 ? "" : digitsToStrings
                .get(numberOfTens * 10) + "";
        break;
    }
    }
    int numberOfOnes = residual - numberOfTens * 10;
    result += numberOfOnes == 0 ? "" : " "
            + digitsToStrings.get(numberOfOnes);
    return result;
}
 
// number is between 0 to 999,999
public static String numberToString(int number) {
    int upper_half = number / 1000;
    int lower_half = number - upper_half * 1000;
    if (upper_half == 0)
        return hundredToString(lower_half);
    else
        return hundredToString(upper_half) + " Thousand, "
                + hundredToString(lower_half);
}

Some test cases for this problem:
  • Acceptance case, an easy case just to see if it's working properly. Like 1234.
  • Zero
  • All numbers are the same digit
  • All numbers are different digits
  • A number with a lot of zeros like 500,000; 30,000; 2000, 100, 90.
  • At least one number in the teens (11-19). This seems to be a tricky case. Make sure your other test data includes digits that end with a teen.
  • Numbers with zeros in the middle: 500,008; 30,012; 908,301. Want to make sure zeros are handled correctly in the middle of the number. Try a zero in at least every position.
  • Numbers less than 1000, to see if it outputs the word "thousand".
  • Numbers with no "hundred" digit, so see if it doesn't out put the word "hundred".
Although this is our custom program, but in real life we shouldn't reinvent the wheel and its best to use already-implemented functions to perform this. ICU4J contains a class com.ibm.icu.text.RuleBasedNumberFormat that can be used to perform this operation. It also supports languages other than English, and the reverse operation, parsing a text string to integer values.


References

Reactions:

0 comments:

Post a Comment