Reputation: 1682
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"
Upvotes: 16
Views: 31071
Reputation: 55
class Application {
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("forty", 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);
}
public static void main(String[] args) {
String input = "fifty five million twenty three thousand ninety one";
System.out.println(wordToNumber(input));
}
private static long wordToNumber(String input) {
String wordsArray[] = input.split(" ");
List<String> words = Arrays.stream(wordsArray).map(String::toLowerCase).collect(Collectors.toList());
long val = 0;
long fResult = 0;
for (String word : words) {
if (word.equalsIgnoreCase("and") || word.equalsIgnoreCase("only")) {
continue;
}
if (numbers.containsKey(word)) {
val = val + numbers.get(word);
} else if (tnumbers.containsKey(word)) {
val = val + tnumbers.get(word);
} else if (onumbers.containsKey(word)) {
fResult = fResult + val * onumbers.get(word);
val = 0;
}
System.out.println("val : " + val);
System.out.println("fresult" + fResult);
}
fResult = fResult + val;
return fResult;
}
}
Upvotes: 0
Reputation: 1459
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"));
Upvotes: 0
Reputation: 4423
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;
}
Upvotes: 0
Reputation: 1
Works for lakhs and crores and ignores "and" .Doesn't handle
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);
}
}
Upvotes: 0
Reputation: 422
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
Upvotes: 0
Reputation: 31
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);
}
}
Upvotes: 3
Reputation: 83
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
Upvotes: 5
Reputation: 1
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));
}
}
Upvotes: -2
Reputation: 986
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!
Upvotes: 0
Reputation: 2985
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:
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);
}
}
Upvotes: 24