简体   繁体   中英

Converting words to numbers in Java

I have seen a lot of algorithms in which you give them a number say "123" and it converts it to One hundred twenty three. But I can't seem to find something that does the opposite, and the ones I did find only do it up to the number 1000. Can anyone direct me in the correct way as what I could do to create a method that takes "One thousand two hundred and thirty four" and gives back "1234"

I hope below code will do the job in most of the cases. However some modification might be required as I've not tested properly yet.

Assumption:

  1. Positive, negative, plus, minus is not allowed.
  2. Lac, crore is not allowed.
  3. Only English language is supported.

If you need to support first two points, you can very easily do that.

    boolean isValidInput = true;
    long result = 0;
    long finalResult = 0;
    List<String> allowedStrings = Arrays.asList
    (
    "zero","one","two","three","four","five","six","seven",
    "eight","nine","ten","eleven","twelve","thirteen","fourteen",
    "fifteen","sixteen","seventeen","eighteen","nineteen","twenty",
    "thirty","forty","fifty","sixty","seventy","eighty","ninety",
    "hundred","thousand","million","billion","trillion"
    );

    String input="One hundred two thousand and thirty four";

    if(input != null && input.length()> 0)
    {
        input = input.replaceAll("-", " ");
        input = input.toLowerCase().replaceAll(" and", " ");
        String[] splittedParts = input.trim().split("\\s+");

        for(String str : splittedParts)
        {
            if(!allowedStrings.contains(str))
            {
                isValidInput = false;
                System.out.println("Invalid word found : "+str);
                break;
            }
        }
        if(isValidInput)
        {
            for(String str : splittedParts)
            {
                if(str.equalsIgnoreCase("zero")) {
                    result += 0;
                }
                else if(str.equalsIgnoreCase("one")) {
                    result += 1;
                }
                else if(str.equalsIgnoreCase("two")) {
                    result += 2;
                }
                else if(str.equalsIgnoreCase("three")) {
                    result += 3;
                }
                else if(str.equalsIgnoreCase("four")) {
                    result += 4;
                }
                else if(str.equalsIgnoreCase("five")) {
                    result += 5;
                }
                else if(str.equalsIgnoreCase("six")) {
                    result += 6;
                }
                else if(str.equalsIgnoreCase("seven")) {
                    result += 7;
                }
                else if(str.equalsIgnoreCase("eight")) {
                    result += 8;
                }
                else if(str.equalsIgnoreCase("nine")) {
                    result += 9;
                }
                else if(str.equalsIgnoreCase("ten")) {
                    result += 10;
                }
                else if(str.equalsIgnoreCase("eleven")) {
                    result += 11;
                }
                else if(str.equalsIgnoreCase("twelve")) {
                    result += 12;
                }
                else if(str.equalsIgnoreCase("thirteen")) {
                    result += 13;
                }
                else if(str.equalsIgnoreCase("fourteen")) {
                    result += 14;
                }
                else if(str.equalsIgnoreCase("fifteen")) {
                    result += 15;
                }
                else if(str.equalsIgnoreCase("sixteen")) {
                    result += 16;
                }
                else if(str.equalsIgnoreCase("seventeen")) {
                    result += 17;
                }
                else if(str.equalsIgnoreCase("eighteen")) {
                    result += 18;
                }
                else if(str.equalsIgnoreCase("nineteen")) {
                    result += 19;
                }
                else if(str.equalsIgnoreCase("twenty")) {
                    result += 20;
                }
                else if(str.equalsIgnoreCase("thirty")) {
                    result += 30;
                }
                else if(str.equalsIgnoreCase("forty")) {
                    result += 40;
                }
                else if(str.equalsIgnoreCase("fifty")) {
                    result += 50;
                }
                else if(str.equalsIgnoreCase("sixty")) {
                    result += 60;
                }
                else if(str.equalsIgnoreCase("seventy")) {
                    result += 70;
                }
                else if(str.equalsIgnoreCase("eighty")) {
                    result += 80;
                }
                else if(str.equalsIgnoreCase("ninety")) {
                    result += 90;
                }
                else if(str.equalsIgnoreCase("hundred")) {
                    result *= 100;
                }
                else if(str.equalsIgnoreCase("thousand")) {
                    result *= 1000;
                    finalResult += result;
                    result=0;
                }
                else if(str.equalsIgnoreCase("million")) {
                    result *= 1000000;
                    finalResult += result;
                    result=0;
                }
                else if(str.equalsIgnoreCase("billion")) {
                    result *= 1000000000;
                    finalResult += result;
                    result=0;
                }
                else if(str.equalsIgnoreCase("trillion")) {
                    result *= 1000000000000L;
                    finalResult += result;
                    result=0;
                }
            }

            finalResult += result;
            result=0;
            System.out.println(finalResult);
        }
    }

Full credit to Kartic for the elegant answer. I've added to it to allow for processing a large block of text with these types of "word numbers" dispersed inside of it. Not as clean as I hoped since I have to process it without losing any formatting.

It's a work in progress but might be of some use to people: https://github.com/jgraham0325/words-to-numbers/blob/master/src/main/java/org/jg/wordstonumbers/WordsToNumbersUtil.java

package com;

import java.util.HashMap;

public class WordNNumber {

    static HashMap<String, Integer> numbers= new HashMap<String, Integer>();

    static HashMap<String, Integer> onumbers= new HashMap<String, Integer>();
    static HashMap<String, Integer> tnumbers= new HashMap<String, Integer>();

    static {
        numbers.put("zero", 0);
        numbers.put("one", 1);
        numbers.put("two", 2);
        numbers.put("three", 3);
        numbers.put("four", 4);
        numbers.put("five", 5);
        numbers.put("six", 6);
        numbers.put("seven", 7);
        numbers.put("eight", 8);
        numbers.put("nine", 9);
        numbers.put("ten", 10);
        numbers.put("eleven", 11);
        numbers.put("twelve", 12);
        numbers.put("thirteen", 13);
        numbers.put("fourteen", 14);
        numbers.put("fifteen", 15);
        numbers.put("sixteen", 16);
        numbers.put("seventeen", 17);
        numbers.put("eighteen", 18);
        numbers.put("nineteen", 19);


        tnumbers.put("twenty", 20);
        tnumbers.put("thirty", 30);
        tnumbers.put("fourty", 40);
        tnumbers.put("fifty", 50);
        tnumbers.put("sixty", 60);
        tnumbers.put("seventy", 70);
        tnumbers.put("eighty", 80);
        tnumbers.put("ninety", 90);

        onumbers.put("hundred", 100);
        onumbers.put("thousand", 1000);
        onumbers.put("million", 1000000);
        onumbers.put("billion", 1000000000);

        //numbers.put("", );
    }

    public static void main(String args[]){
        String input1="fifty five million twenty three thousand ninety one";
        String input2="fifty five billion three thousand one";
        String input3="fifty five million ninety one";

        wordToNumber(input1);
        wordToNumber(input2);
        wordToNumber(input3);


    }

    private static void wordToNumber(String input) {
        System.out.println("===========\nInput string = "+input);
        long sum=0;
        Integer temp=null;
        Integer previous=0;
        String [] splitted= input.toLowerCase().split(" ");


        for(String split:splitted){

            if( numbers.get(split)!=null){
                temp= numbers.get(split);

                sum=sum+temp;

                previous=previous+temp;
            }
            else if(onumbers.get(split)!=null){
                if(sum!=0){
                    sum=sum-previous;
                }
                sum=sum+(long)previous*(long)onumbers.get(split);
                temp=null;
                previous=0;


            }
            else if(tnumbers.get(split)!=null){
                temp=tnumbers.get(split);
                sum=sum+temp;

                previous=temp;
            }

        }

        System.out.println(sum);
    }

}

Okay, I think I've gotten something.

There is a variable called 'debug', when the number produces doesn't work like it should please set this to true and do the following things:
1) Give me the string you used and the number you expected
2) Give me the log it produces
3) Be patient

If you want numbers above 1 trillion (which I can't imagine, but well) please tell me what that number is called ;)

The code:

    boolean debug=true;
    String word="";

    // All words below and others should work
    //word="One thousand two hundred thirty four"; //1234
    //word="Twenty-one hundred thirty one"; //2131
    //word="Forty-three thousand seven hundred fifty one"; //43751
    //word="Nineteen thousand eighty"; // 19080
    //word="five-hundred-forty-three thousand two hundred ten"; //543210
    //word="ninety-eight-hundred-seventy-six thousand"; // 9876000

    // Max:
    word="nine-hundred-ninety-nine trillion nine-hundred-ninety-nine billion nine-hundred-ninety-nine million nine-hundred-ninety-nine thousand nine hundred ninety nine";


    word=word.toLowerCase().trim();

    String oldWord="";
    while(word!=oldWord) {
        oldWord=word;
        word=word.replace("  "," ");
    }

    String[] data=word.split(" ");

    HashMap<String, Long> database=new HashMap<String, Long>();
    database.put("zero", 0L);
    database.put("one", 1L);
    database.put("two", 2L);
    database.put("three", 3L);
    database.put("four", 4L);
    database.put("five", 5L);
    database.put("six", 6L);
    database.put("seven", 7L);
    database.put("eight", 8L);
    database.put("nine", 9L);

    database.put("ten", 10L);
    database.put("hundred", 100L);
    database.put("thousand", 1000L);
    database.put("million", 1000000L);
    database.put("billion", 1000000000L);
    database.put("trillion", 1000000000000L);

    // Exceptional prefixes
    database.put("twen", 2L);
    database.put("thir", 3L);
    database.put("for", 4L);
    database.put("fif", 5L);
    database.put("eigh", 8L);

    // Other exceptions
    database.put("eleven", 11L);
    database.put("twelve", 12L);


    boolean negative=false;
    long sum=0;
    for(int i=0; i<data.length; i+=2) {

        long first=0;
        long second=1;

        try {
            if(data[i].equals("minus")) {
                if(debug) System.out.println("negative=true");
                negative=true;
                i--;
            } else if(data[i].endsWith("ty")) {
                first=database.get(data[i].split("ty")[0])*10;
                i--;
            } else if(data[i].endsWith("teen")) {
                first=database.get(data[i].split("teen")[0])+10;
                if(data.length>i+1)
                    if(database.get(data[i+1])%10!=0)
                        i--;
                    else
                        second=database.get(data[i+1]);
            } else if(data[i].contains("-")){
                String[] moreData=data[i].split("-");

                long a=0;
                long b=0;

                if(moreData[0].endsWith("ty")) {
                    a=database.get(moreData[0].split("ty")[0])*10;
                } else {
                    a=database.get(moreData[0]);
                }

                if(debug) System.out.println("a="+a);

                b=database.get(moreData[1]);
                if(b%10==0)
                    first=a*b;
                else
                    first=a+b;

                if(debug) System.out.println("b="+b);

                if(moreData.length>2) {
                    for(int z=2; z<moreData.length; z+=2) {
                        long d=0;
                        long e=0;

                        if(moreData[z].endsWith("ty")) {
                            d=database.get(moreData[z].split("ty")[0])*10;
                        } else {
                            d=database.get(moreData[z]);
                        }

                        if(debug) System.out.println("d="+d);

                        if(d%100==0) {
                            first*=d;
                            z--;
                        } else {
                            e=database.get(moreData[z+1]);
                            if(e%10==0)
                                first+=d*e;
                            else
                                first+=d+e;
                            if(debug) System.out.println("e="+e);
                        }
                    }
                }

                second=database.get(data[i+1]);

            } else if(word.length()>0){
                first=database.get(data[i]);
                if(data.length>i+1)
                    second=database.get(data[i+1]);
            } else {
                System.err.println("You didn't even enter a word :/");
            }

            if(debug) System.out.println("first="+first);
            if(debug) System.out.println("second="+second);

        } catch(Exception e) {
            System.out.println("[Debug Info, Ignore] Couldn't parse "+i+"["+data[i]+"]");
            e.printStackTrace(System.out);
        }

        sum+=first*second;
    }
    if(negative)
        sum*=-1;

    System.out.println("Result: "+sum);

Let me know if it works and don't forget to give feedback. (Both positive and negative)
Happy coding :) -Charlie PS: My native language isn't English, but this works as I should write numbers. Let me know if it isn't!

I have done another implementation of the same using HashMap to store the numbers and avoiding if else in a statement.

Assumptions: Negative numbers not handled

Code:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class TranslateSentenceTonumber2 {

public static void main(String[] args) {
    initFIRSTTWENTY();

    String sentence1 = "I have twenty thousand twenti two rupees";
    translateNumber(sentence1);
  
    String sentence4 = "one hundred ten thousand";
    translateNumber(sentence4);

    String sentence5 = "one hundred forty seven";
    translateNumber(sentence4 + " " +sentence5);
}

private static HashMap<String, Integer> FIRSTTWENTY;

private static final String SPACES_SPLIT = "\\s+";

private static void translateNumber(String playSentence){
    String sentence = playSentence;
    HashMap<String, Long> CALCULATION = new HashMap<>();
    Set<String > ALLOWED = new HashSet<>(FIRSTTWENTY.keySet());
    ALLOWED.add("hundred");
    ALLOWED.add("thousand");
    ALLOWED.add("million");
    if (sentence != null && sentence.length() >0) {
        sentence = sentence.replace("-", " ");
        String [] splittedString = sentence.split(SPACES_SPLIT);
        String continuousString = "";
        int length = splittedString.length;
        for (int i=0; i<length; i++){
            String str  = splittedString[i];
            if (ALLOWED.contains(str.toLowerCase()) && !continuousString.trim().equalsIgnoreCase(str)){
                continuousString = continuousString.trim() + " " + str;
                if (i== length-1){
                    CALCULATION.put(continuousString.trim(), null);
                    continuousString = "";
                }
            }
            if (!ALLOWED.contains(str.toLowerCase()) && !continuousString.trim().isEmpty()) {
                CALCULATION.put(continuousString.trim(), null);
                continuousString = "";
            }
        }

        CALCULATION.replaceAll((c, v) -> calculation(c));

        for(String calc : CALCULATION.keySet()){
            playSentence = playSentence.replace(calc, "" +CALCULATION.get(calc));
        }
        System.out.println(playSentence);
    }
}

private static long calculation(String input){
    long inBetweenCalculation = 0;
    long output = 0;
    if (input != null && !input.isEmpty()) {
        String [] array = input.split(SPACES_SPLIT);
        for (String str: array) {
            if (FIRSTTWENTY.containsKey(str.toLowerCase())) {
                inBetweenCalculation += FIRSTTWENTY.get(str.toLowerCase());
            } else if ("hundred".equalsIgnoreCase(str)) {
                inBetweenCalculation *= 100;
            } else if ("thousand".equalsIgnoreCase(str)) {
                inBetweenCalculation *= 1000;
                output += inBetweenCalculation;
                inBetweenCalculation = 0;
            } else if ("million".equalsIgnoreCase(str)) {
                inBetweenCalculation *= 1000000;
                output += inBetweenCalculation;
                inBetweenCalculation = 0;
            }
        }
        output += inBetweenCalculation;
    }
    return output;
}


private static void initFIRSTTWENTY(){
    FIRSTTWENTY = new HashMap<>();
    FIRSTTWENTY.put("zero", 0);
    FIRSTTWENTY.put("one", 1);FIRSTTWENTY.put("eleven", 11);
    FIRSTTWENTY.put("two", 2);FIRSTTWENTY.put("twelve", 12);
    FIRSTTWENTY.put("three", 3);FIRSTTWENTY.put("thirteen", 13);
    FIRSTTWENTY.put("four", 4);FIRSTTWENTY.put("fourteen", 14);
    FIRSTTWENTY.put("five", 5);FIRSTTWENTY.put("fifteen", 15);
    FIRSTTWENTY.put("six", 6);FIRSTTWENTY.put("sixteen", 16);
    FIRSTTWENTY.put("seven", 7);FIRSTTWENTY.put("seventeen", 17);
    FIRSTTWENTY.put("eight", 8);FIRSTTWENTY.put("eighteen", 18);
    FIRSTTWENTY.put("nine", 9);FIRSTTWENTY.put("nineteen", 19);
    FIRSTTWENTY.put("ten", 10);FIRSTTWENTY.put("twenty", 20);
    FIRSTTWENTY.put("thirty", 30);FIRSTTWENTY.put("forty", 40);
    FIRSTTWENTY.put("fifty", 50);FIRSTTWENTY.put("sixty", 60);
    FIRSTTWENTY.put("seventy", 70);FIRSTTWENTY.put("eighty", 80);
    FIRSTTWENTY.put("ninety", 90);
}
}

Output:

I have 20000 twenti 2 rupees

110000

110147

Works for lakhs and crores and ignores "and" .Doesn't handle

  1. Invalid cases like "eight "and" crores".
  2. Inputs like " fifty billion crores"
    boolean isValidInput = true;
    long result = 0;
    long finalResult = 0;
    List<String> allowedStrings = Arrays.asList
    (
    "zero","one","two","three","four","five","six","seven",
    "eight","nine","ten","eleven","twelve","thirteen","fourteen",
    "fifteen","sixteen","seventeen","eighteen","nineteen","twenty",
    "thirty","forty","fifty","sixty","seventy","eighty","ninety",
    "hundred","lakhs","lakh","thousand","crore","crores","and",
    "million","billion","trillion"
    );

    //String input="one hundred";
    String input = String.join(" ", args);
    if(input != null && input.length()> 0)
    {
        input = input.replaceAll("-", " ");
        input = input.toLowerCase().replaceAll(" and", " ");
        String[] splittedParts = input.trim().split("\\s+");

        for(String str : splittedParts)
        {
            if(!allowedStrings.contains(str))
            {
                isValidInput = false;
                System.out.println("Invalid word found : "+str);
                break;
            }
        }
        if(isValidInput)
        {
            for(String str : splittedParts)
            {
                String compare=str.toLowerCase();
                switch(compare){
                case "and":break;
                case "zero":result += 0;
                            break;
                case "one":result += 1;
                           break;
                
                case "two":result += 2;
                           break;
                case "three":result += 3;
                           break;
                case "four":result += 4;
                           break; 
                case "five":result += 5;
                           break;  
                case "six":result += 6;
                           break;
                case "seven":result += 7;
                           break;
                case "eight":result += 8;
                           break;
                case "nine":result += 9;
                           break;
                case "ten":result += 10;
                           break;
                case "eleven":result += 11;
                           break;
                case "twelve":result += 12;
                           break;
                case "thirteen":result += 13;
                           break;
                case "fourteen":result += 14;
                           break;
                case "fifteen":result += 15;
                           break;
                case "sixteen":result += 16;
                           break;
                case "seventeen":result += 17;
                           break;
                case "eighteen":result += 18;
                           break;
                case "nineteen":result += 19;
                           break;
                case "twenty":result += 20;
                           break;
                case "thirty":result += 30;
                           break;
                case "forty":result += 40;
                           break;
                case "fifty":result += 50;
                           break;
                case "sixty":result += 60;
                           break;
                case "seventy":result += 70;
                           break;
                case "eighty":result += 80;
                           break;
                case "ninety":result += 90;
                           break;
                case "hundred":result *= 100;
                           break;
                case "thousand":result *= 1000;
                           finalResult += result;
                           result=0;
                           break;
                case "lakh":result *= 100000;
                           finalResult += result;
                           result=0;
                           break;
                case "lakhs":result *= 100000;
                           finalResult += result;
                           result=0;
                           break;
                case "crore":result *= 10000000;
                           finalResult += result;
                           result=0;
                           break;   
                case "crores":result *= 10000000;
                           finalResult += result;
                           result=0;
                           break;
                case "million":result *= 1000000;
                           finalResult += result;
                           result=0;
                           break;
                case "billion":result *= 1000000000;
                           finalResult += result;
                           result=0;
                           break;
                case "trillion":result *= 1000000000000L;
                           finalResult += result;
                           result=0;
                           break;
                }
            }

            finalResult += result;
            result=0;
            System.out.println(finalResult);
        }
    }

an alternative :)

enum numbers {
    zero,
    one,
    two,
    three,
    four,
    five,
    six,
    eight,
    nine
}

public static String parseNumbers(String text) {

    String out = "";
    for(String s: text.split(" ")) {
        out += numbers.valueOf(s).ordinal();
    }
    return out;
}

I've ended up with this solution. It's for numbers between zero to one million (can be enhanced easily), can support dash / and / just numbers.

public int parseInt(String number) {
    //Edge cases
    if("one million".equals(number)) return 1000000;
    if("zero".equals(number)) return 0;
    
    String[] splitted = number.split("thousand");
    String hundreds = splitted.length == 1 ? splitted[0].trim() : splitted[1].trim();
    
    int resultRight = calculateTriplet(hundreds);
    
    //X thousand case
    if(splitted.length == 1) {
        if(number.contains("thousand"))
            return resultRight*1000;
        return resultRight;
    }
    
    String thous = splitted[0].trim();
    int resultLeft = calculateTriplet(thous) * 1000;
    
    return resultLeft+resultRight;
}

private int calculateTriplet(String hundreds) {
    String[] triplet = hundreds.split(" |-");
    int result = 0;
    for (int i=0;i<triplet.length;i++) {
        result *= triplet[i].equals("hundred") ? 100 : 1;
        result += upTo19.indexOf(triplet[i]) != -1 ? 
                upTo19.indexOf(triplet[i]) 
                : tens.indexOf(triplet[i]) != -1 ?
                        tens.indexOf(triplet[i])*10 :
                            0;
    }
    return result;
}

  private static final List<String> tens = new ArrayList<String> (Arrays.asList(
            "","ten","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"));

 private static final List<String> upTo19 = new ArrayList<String> (Arrays.asList(
            "","one","two","three","four","five","six","seven","eight","nine", "ten","eleven","twelve","thirteen",
            "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"));

Best and simple way to print 0 to 99999 numbers to words conversion program

Note: You can also extend more numbers greater than 99999 using same logic.

import java.util.Scanner;
class NumberToWord
{  
    final private static String[]units = {"Zero", "One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten",
    "Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"};

    final private static String[]tens = {"","","Twenty ","Thirty ","Forty ","Fifty ","Sixty ","Seventy ","Eighty ","Ninety "};
    public static String convert(int number)
    {
            if(number<0)
            {
                throw new ArithmeticException("Number should be positive.");            
            }
            else if(number<20)
            {
                return (units[number]);
            }   
            else if(number<100)
            {
                return tens[number/10] + ((number % 10 > 0)? convert(number % 10):"");
            }           
            else if(number<1000)
            {
                return units[number/100] + " hundred" + ((number%100>0)? " and " + convert(number%100):"");
            }           
            else if(number<20000)
            {
                return  units[number/1000] + " Thousand " + ((number%1000>0)? convert(number%1000):"");
            }           
                return tens[number/10000] + ((number%10000>0)? convert(number%10000):"Thousand" );      
    }   

    public static void main(String[] args) 
    {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter a number between 0 to 99999: ");
        int num = sc.nextInt();
        System.out.println(convert(num));   
    }    
}

Thank you for reading!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM