From a5b4072db69caecd9e05901413affaa9f5392bb7 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 07:40:51 +0530 Subject: [PATCH 01/15] Add feature to convert numeric words to their number representation --- DIRECTORY.md | 2 + .../conversions/WordsToNumber.java | 185 ++++++++++++++++++ .../conversions/WordsToNumberTest.java | 86 ++++++++ 3 files changed, 273 insertions(+) create mode 100644 src/main/java/com/thealgorithms/conversions/WordsToNumber.java create mode 100644 src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java diff --git a/DIRECTORY.md b/DIRECTORY.md index f53a6220c517..fe9e440da3e2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -118,6 +118,7 @@ * [TurkishToLatinConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java) * [UnitConversions](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/UnitConversions.java) * [UnitsConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/UnitsConverter.java) + * [WordsToNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/WordsToNumber.java) * datastructures * bags * [Bag](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/bags/Bag.java) @@ -840,6 +841,7 @@ * [TurkishToLatinConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/TurkishToLatinConversionTest.java) * [UnitConversionsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/UnitConversionsTest.java) * [UnitsConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java) + * [WordsToNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java) * datastructures * bag * [BagTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java new file mode 100644 index 000000000000..2f90eb8b15a7 --- /dev/null +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -0,0 +1,185 @@ +package com.thealgorithms.conversions; + +import java.math.BigDecimal; +import java.util.*; + +public final class WordsToNumber { + private WordsToNumber() { + } + + private static final HashMap NUMBER_MAP = new HashMap<>(); + private static final HashMap POWERS_OF_TEN = new HashMap<>(); + + static { + NUMBER_MAP.put("zero", 0); + NUMBER_MAP.put("one", 1); + NUMBER_MAP.put("two", 2); + NUMBER_MAP.put("three", 3); + NUMBER_MAP.put("four", 4); + NUMBER_MAP.put("five", 5); + NUMBER_MAP.put("six", 6); + NUMBER_MAP.put("seven", 7); + NUMBER_MAP.put("eight", 8); + NUMBER_MAP.put("nine", 9); + NUMBER_MAP.put("ten", 10); + NUMBER_MAP.put("eleven", 11); + NUMBER_MAP.put("twelve", 12); + NUMBER_MAP.put("thirteen", 13); + NUMBER_MAP.put("fourteen", 14); + NUMBER_MAP.put("fifteen", 15); + NUMBER_MAP.put("sixteen", 16); + NUMBER_MAP.put("seventeen", 17); + NUMBER_MAP.put("eighteen", 18); + NUMBER_MAP.put("nineteen", 19); + NUMBER_MAP.put("twenty", 20); + NUMBER_MAP.put("thirty", 30); + NUMBER_MAP.put("forty", 40); + NUMBER_MAP.put("fifty", 50); + NUMBER_MAP.put("sixty", 60); + NUMBER_MAP.put("seventy", 70); + NUMBER_MAP.put("eighty", 80); + NUMBER_MAP.put("ninety", 90); + + POWERS_OF_TEN.put("thousand", new BigDecimal("1000")); + POWERS_OF_TEN.put("million", new BigDecimal("1000000")); + POWERS_OF_TEN.put("billion", new BigDecimal("1000000000")); + POWERS_OF_TEN.put("trillion", new BigDecimal("1000000000000")); + } + + public static String convert(String numberInWords) { + if (numberInWords == null) return "Null Input"; + + String[] wordSplitArray = numberInWords.trim().split("[ ,-]"); + ArrayDeque wordDeque = new ArrayDeque<>(); + for (String word : wordSplitArray) { + if (word.isEmpty()) continue; + wordDeque.add(word.toLowerCase()); + } + + List chunks = new ArrayList<>(); + BigDecimal currentChunk = BigDecimal.ZERO; + + boolean isNegative = false; + boolean prevNumWasHundred = false; + boolean prevNumWasPowerOfTen = false; + + while (!wordDeque.isEmpty()) { + String word = wordDeque.poll(); + boolean currentChunkIsZero = currentChunk.equals(BigDecimal.ZERO); + + boolean isConjunction = word.equals("and"); + if (isConjunction && isValidConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque)) continue; + + boolean isHundred = word.equals("hundred"); + if (isHundred) { + if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) return "Invalid Input. Unexpected Word: " + word; + if (currentChunkIsZero) currentChunk = currentChunk.add(BigDecimal.ONE); + currentChunk = currentChunk.multiply(BigDecimal.valueOf(100)); + prevNumWasHundred = true; + continue; + } + prevNumWasHundred = false; + + BigDecimal powerOfTen = POWERS_OF_TEN.getOrDefault(word, null); + if (powerOfTen != null) { + if (currentChunkIsZero || prevNumWasPowerOfTen) return "Invalid Input. Unexpected Word: " + word; + BigDecimal nextChunk = currentChunk.multiply(powerOfTen); + + if (chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk)) + chunks.add(nextChunk); + else + return "Invalid Input. Unexpected Word: " + word; + currentChunk = BigDecimal.ZERO; + prevNumWasPowerOfTen = true; + continue; + } + prevNumWasPowerOfTen = false; + + Integer number = NUMBER_MAP.getOrDefault(word, null); + if (number != null) { + if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) return "Invalid Input. Unexpected word: " + word; + BigDecimal bigDecimalNumber = BigDecimal.valueOf(number); + + if (currentChunkIsZero || isAdditionSafe(currentChunk, bigDecimalNumber)) + currentChunk = currentChunk.add(bigDecimalNumber); + else + return "Invalid Input. Unexpected word: " + word; + continue; + } + + if (word.equals("point")) { + if (!currentChunkIsZero) chunks.add(currentChunk); + currentChunk = BigDecimal.ZERO; + + String decimalPart = convertDecimalPart(wordDeque); + if (!decimalPart.startsWith("I")) + chunks.add(new BigDecimal(decimalPart)); + else + return decimalPart; + break; + } + + if (word.equals("negative")) { + if (isNegative) return "Invalid Input. Multiple 'Negative's detected."; + isNegative = chunks.isEmpty() && currentChunkIsZero; + continue; + } + + return "Invalid Input. " + (isConjunction ? "Unexpected 'and' placement" : "Unknown Word: " + word); + } + + if (!currentChunk.equals(BigDecimal.ZERO)) chunks.add(currentChunk); + BigDecimal completeNumber = combineChunks(chunks); + + return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1)).toString() : completeNumber.toString(); + } + + private static boolean isValidConjunction(boolean prevNumWasHundred, boolean prevNumWasPowerOfTen, ArrayDeque wordDeque) { + if (wordDeque.isEmpty()) return false; + + String nextWord = wordDeque.pollFirst(); + String afterNextWord = wordDeque.peekFirst(); + + wordDeque.addFirst(nextWord); + + Integer number = NUMBER_MAP.getOrDefault(nextWord, null); + + boolean isPrevWordValid = prevNumWasHundred || prevNumWasPowerOfTen; + boolean isNextWordValid = number != null && (number >= 10 || afterNextWord == null || afterNextWord.equals("point")); + + return isPrevWordValid && isNextWordValid; + } + + private static boolean isAdditionSafe(BigDecimal currentChunk, BigDecimal number) { + int chunkDigitCount = currentChunk.toString().length(); + int numberDigitCount = number.toString().length(); + return chunkDigitCount > numberDigitCount; + } + + private static String convertDecimalPart(Queue wordDeque) { + StringBuilder decimalPart = new StringBuilder("."); + while (!wordDeque.isEmpty()) { + String word = wordDeque.poll(); + Integer number = NUMBER_MAP.getOrDefault(word, null); + if (number != null) + decimalPart.append(number); + else + return "Invalid Input. Unexpected Word (after Point): " + word; + } + + if (decimalPart.length() == 1) return "Invalid Input. Decimal Part is missing Numbers."; + return decimalPart.toString(); + } + + private static BigDecimal combineChunks(List chunks) { + BigDecimal completeNumber = BigDecimal.ZERO; + for (BigDecimal chunk : chunks) completeNumber = completeNumber.add(chunk); + return completeNumber; + } + + public static BigDecimal convertToBigDecimal(String numberInWords) { + String conversionResult = convert(numberInWords); + if (conversionResult.startsWith("I")) return null; + return new BigDecimal(conversionResult); + } +} diff --git a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java new file mode 100644 index 000000000000..b423a3396ca6 --- /dev/null +++ b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java @@ -0,0 +1,86 @@ +package com.thealgorithms.conversions; + +import static org.junit.jupiter.api.Assertions.*; + +import java.math.BigDecimal; +import org.junit.jupiter.api.Test; + +public class WordsToNumberTest { + + @Test + void testNullInput() { + assertEquals("Null Input", WordsToNumber.convert(null), "Null input should return 'Null Input'"); + } + + @Test + void testStandardCases() { + assertEquals("0", WordsToNumber.convert("zero"), "'zero' should convert to '0'"); + assertEquals("5", WordsToNumber.convert("five"), "'five' should convert to '5'"); + assertEquals("21", WordsToNumber.convert("twenty one"), "'twenty one' should convert to '21'"); + assertEquals("101", WordsToNumber.convert("one hundred one"), "'one hundred' should convert to '101'"); + assertEquals("342", WordsToNumber.convert("three hundred and forty two"), "'three hundred and forty two' should convert to '342'"); + } + + @Test + void testLargeNumbers() { + assertEquals("1000000", WordsToNumber.convert("one million"), "'one million' should convert to '1000000'"); + assertEquals("1000000000", WordsToNumber.convert("one billion"), "'one billion' should convert to '1000000000'"); + assertEquals("1000000000000", WordsToNumber.convert("one trillion"), "'one trillion' should convert to '1000000000000'"); + assertEquals("999000000900999", WordsToNumber.convert("nine hundred ninety nine trillion nine hundred thousand nine hundred and ninety nine"), "'nine hundred ninety nine trillion nine hundred thousand nine hundred and ninety nine' should convert to '999000000900999'"); + } + + @Test + void testNegativeNumbers() { + assertEquals("-5", WordsToNumber.convert("negative five"), "'negative five' should convert to '-5'"); + assertEquals("-120", WordsToNumber.convert("negative one hundred and twenty"), "'negative one hundred and twenty' should convert correctly"); + } + + @Test + void testNegativeLargeNumbers() { + assertEquals("-1000000000000", WordsToNumber.convert("negative one trillion"), "'negative one trillion' should convert to '-1000000000000'"); + assertEquals("-9876543210987", WordsToNumber.convert("Negative Nine Trillion Eight Hundred Seventy Six Billion Five Hundred Forty Three Million Two Hundred Ten Thousand Nine Hundred Eighty Seven"), ""); + } + + @Test + void testDecimalNumbers() { + assertEquals("3.1415", WordsToNumber.convert("three point one four one five"), "'three point one four one five' should convert to '3.1415'"); + assertEquals("-2.718", WordsToNumber.convert("negative two point seven one eight"), "'negative two point seven one eight' should convert to '-2.718'"); + assertEquals("-1E-7", WordsToNumber.convert("negative zero point zero zero zero zero zero zero one"), "'negative zero point zero zero zero zero zero zero one' should convert to '-1E-7'"); + } + + @Test + void testLargeDecimalNumbers() { + assertEquals("1000000000.000000001", WordsToNumber.convert("one billion point zero zero zero zero zero zero zero zero zero one"), "Tests a large whole number with a tiny fractional part"); + assertEquals("999999999999999.999999999999999", + WordsToNumber.convert("nine hundred ninety nine trillion nine hundred ninety nine billion nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine point nine nine nine nine nine nine nine nine nine nine nine nine nine"), + "Tests maximum scale handling for large decimal numbers"); + assertEquals("0.505", WordsToNumber.convert("zero point five zero five"), "Tests a decimal with an internal zero, ensuring correct parsing"); + assertEquals("42.00000000000001", WordsToNumber.convert("forty two point zero zero zero zero zero zero zero zero zero zero zero zero zero one"), "Tests a decimal with leading zeros before a significant figure"); + assertEquals("7.89E-7", WordsToNumber.convert("zero point zero zero zero zero zero zero seven eight nine"), "Tests scientific notation for a small decimal with multiple digits"); + assertEquals("0.999999", WordsToNumber.convert("zero point nine nine nine nine nine nine"), "Tests a decimal close to one with multiple repeated digits"); + } + + @Test + void testCaseInsensitivity() { + assertEquals("21", WordsToNumber.convert("TWENTY-ONE"), "Uppercase should still convert correctly"); + assertEquals("-100.0001", WordsToNumber.convert("negAtiVe OnE HuNdReD, point ZeRO Zero zERo ONE"), "Mixed case should still convert correctly"); + assertEquals("-225647.00019", WordsToNumber.convert("nEgative twO HundRed, and twenty-Five thOusaNd, six huNdred Forty-Seven, Point zero zero zero One nInE")); + } + + @Test + void testInvalidInputs() { + assertEquals("Invalid Input. Unknown Word: alpha", WordsToNumber.convert("negative one hundred AlPha"), "'AlPha' is not a valid word"); + assertEquals("Invalid Input. Unexpected Word: thirteen", WordsToNumber.convert("twenty thirteen"), "'twenty thirteen' is not a valid format"); + assertEquals("Invalid Input. Multiple 'Negative's detected.", WordsToNumber.convert("negative negative ten"), "Should detect multiple negatives"); + assertEquals("Invalid Input. Unexpected Word: hundred", WordsToNumber.convert("one hundred hundred"), "Direct repetition of 'hundred' is invalid"); + assertEquals("Invalid Input. Unexpected 'and' placement", WordsToNumber.convert("one thousand and hundred"), "Detects invalid 'and' placement"); + assertEquals("Invalid Input. Unexpected Word: hundred", WordsToNumber.convert("one thousand hundred"), "Detects incorrect placement of powers of ten"); + assertEquals("Invalid Input. Unexpected 'and' placement", WordsToNumber.convert("nine hundred and nine hundred"), "Detects invalid 'and' placement"); + } + + @Test + void testConvertToBigDecimal() { + assertEquals(new BigDecimal("-100000000000000.056"), WordsToNumber.convertToBigDecimal("negative one hundred trillion point zero five six"), "should convert to appropriate BigDecimal value"); + assertNull(WordsToNumber.convertToBigDecimal("invalid input"), "Invalid input should return null"); + } +} From 3d5831219e3371158f730f41d90c3f0aaba224bb Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 08:33:25 +0530 Subject: [PATCH 02/15] solve build error --- .../thealgorithms/conversions/WordsToNumber.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 2f90eb8b15a7..8ee2cf079442 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -3,6 +3,15 @@ import java.math.BigDecimal; import java.util.*; +/** + A Java-based utility for converting English word representations of numbers + into their numeric form. This utility supports whole numbers, decimals, + large values up to trillions, and even scientific notation where applicable. + It ensures accurate parsing while handling edge cases like negative numbers, + improper word placements, and ambiguous inputs. + * + */ + public final class WordsToNumber { private WordsToNumber() { } @@ -97,13 +106,13 @@ public static String convert(String numberInWords) { Integer number = NUMBER_MAP.getOrDefault(word, null); if (number != null) { - if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) return "Invalid Input. Unexpected word: " + word; + if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) return "Invalid Input. Unexpected Word: " + word; BigDecimal bigDecimalNumber = BigDecimal.valueOf(number); if (currentChunkIsZero || isAdditionSafe(currentChunk, bigDecimalNumber)) currentChunk = currentChunk.add(bigDecimalNumber); else - return "Invalid Input. Unexpected word: " + word; + return "Invalid Input. Unexpected Word: " + word; continue; } From d30c6c807bae44a7efe00b96a4e1bec782141eb5 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 08:37:55 +0530 Subject: [PATCH 03/15] solving build error #2 --- .../java/com/thealgorithms/conversions/WordsToNumberTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java index b423a3396ca6..07b69f275e6d 100644 --- a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java +++ b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java @@ -50,7 +50,7 @@ void testDecimalNumbers() { @Test void testLargeDecimalNumbers() { - assertEquals("1000000000.000000001", WordsToNumber.convert("one billion point zero zero zero zero zero zero zero zero zero one"), "Tests a large whole number with a tiny fractional part"); + assertEquals("1000000000.0000000001", WordsToNumber.convert("one billion point zero zero zero zero zero zero zero zero zero one"), "Tests a large whole number with a tiny fractional part"); assertEquals("999999999999999.999999999999999", WordsToNumber.convert("nine hundred ninety nine trillion nine hundred ninety nine billion nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine point nine nine nine nine nine nine nine nine nine nine nine nine nine"), "Tests maximum scale handling for large decimal numbers"); From 75dfd9e6dbacdde30861755c72d1893f274a1b99 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 08:46:13 +0530 Subject: [PATCH 04/15] solve build error #3 --- .../java/com/thealgorithms/conversions/WordsToNumberTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java index 07b69f275e6d..380ab562c370 100644 --- a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java +++ b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java @@ -51,7 +51,7 @@ void testDecimalNumbers() { @Test void testLargeDecimalNumbers() { assertEquals("1000000000.0000000001", WordsToNumber.convert("one billion point zero zero zero zero zero zero zero zero zero one"), "Tests a large whole number with a tiny fractional part"); - assertEquals("999999999999999.999999999999999", + assertEquals("999999999999999.9999999999999", WordsToNumber.convert("nine hundred ninety nine trillion nine hundred ninety nine billion nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine point nine nine nine nine nine nine nine nine nine nine nine nine nine"), "Tests maximum scale handling for large decimal numbers"); assertEquals("0.505", WordsToNumber.convert("zero point five zero five"), "Tests a decimal with an internal zero, ensuring correct parsing"); From 0b47db6d7d0bf07cef1a0971ed4066ea583a3bcf Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 09:03:08 +0530 Subject: [PATCH 05/15] solve build error, fix checkstyle issues --- .../conversions/WordsToNumber.java | 84 ++++++++++++++----- .../conversions/WordsToNumberTest.java | 3 +- 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 8ee2cf079442..e984b8e7a101 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -1,7 +1,11 @@ package com.thealgorithms.conversions; import java.math.BigDecimal; -import java.util.*; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + /** A Java-based utility for converting English word representations of numbers @@ -56,12 +60,16 @@ private WordsToNumber() { } public static String convert(String numberInWords) { - if (numberInWords == null) return "Null Input"; + if (numberInWords == null) { + return "Null Input"; + } String[] wordSplitArray = numberInWords.trim().split("[ ,-]"); ArrayDeque wordDeque = new ArrayDeque<>(); for (String word : wordSplitArray) { - if (word.isEmpty()) continue; + if (word.isEmpty()) { + continue; + } wordDeque.add(word.toLowerCase()); } @@ -77,12 +85,18 @@ public static String convert(String numberInWords) { boolean currentChunkIsZero = currentChunk.equals(BigDecimal.ZERO); boolean isConjunction = word.equals("and"); - if (isConjunction && isValidConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque)) continue; + if (isConjunction && isValidConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque)) { + continue; + } boolean isHundred = word.equals("hundred"); if (isHundred) { - if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) return "Invalid Input. Unexpected Word: " + word; - if (currentChunkIsZero) currentChunk = currentChunk.add(BigDecimal.ONE); + if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) { + return "Invalid Input. Unexpected Word: " + word; + } + if (currentChunkIsZero) { + currentChunk = currentChunk.add(BigDecimal.ONE); + } currentChunk = currentChunk.multiply(BigDecimal.valueOf(100)); prevNumWasHundred = true; continue; @@ -91,13 +105,17 @@ public static String convert(String numberInWords) { BigDecimal powerOfTen = POWERS_OF_TEN.getOrDefault(word, null); if (powerOfTen != null) { - if (currentChunkIsZero || prevNumWasPowerOfTen) return "Invalid Input. Unexpected Word: " + word; + if (currentChunkIsZero || prevNumWasPowerOfTen) { + return "Invalid Input. Unexpected Word: " + word; + } BigDecimal nextChunk = currentChunk.multiply(powerOfTen); - if (chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk)) + if (chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk)) { chunks.add(nextChunk); - else + } + else { return "Invalid Input. Unexpected Word: " + word; + } currentChunk = BigDecimal.ZERO; prevNumWasPowerOfTen = true; continue; @@ -106,30 +124,40 @@ public static String convert(String numberInWords) { Integer number = NUMBER_MAP.getOrDefault(word, null); if (number != null) { - if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) return "Invalid Input. Unexpected Word: " + word; + if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) { + return "Invalid Input. Unexpected Word: " + word; + } BigDecimal bigDecimalNumber = BigDecimal.valueOf(number); - if (currentChunkIsZero || isAdditionSafe(currentChunk, bigDecimalNumber)) + if (currentChunkIsZero || isAdditionSafe(currentChunk, bigDecimalNumber)) { currentChunk = currentChunk.add(bigDecimalNumber); - else + } + else { return "Invalid Input. Unexpected Word: " + word; + } continue; } if (word.equals("point")) { - if (!currentChunkIsZero) chunks.add(currentChunk); + if (!currentChunkIsZero) { + chunks.add(currentChunk); + } currentChunk = BigDecimal.ZERO; String decimalPart = convertDecimalPart(wordDeque); - if (!decimalPart.startsWith("I")) + if (!decimalPart.startsWith("I")) { chunks.add(new BigDecimal(decimalPart)); - else + } + else { return decimalPart; + } break; } if (word.equals("negative")) { - if (isNegative) return "Invalid Input. Multiple 'Negative's detected."; + if (isNegative) { + return "Invalid Input. Multiple 'Negative's detected."; + } isNegative = chunks.isEmpty() && currentChunkIsZero; continue; } @@ -137,14 +165,18 @@ public static String convert(String numberInWords) { return "Invalid Input. " + (isConjunction ? "Unexpected 'and' placement" : "Unknown Word: " + word); } - if (!currentChunk.equals(BigDecimal.ZERO)) chunks.add(currentChunk); + if (!currentChunk.equals(BigDecimal.ZERO)) { + chunks.add(currentChunk); + } BigDecimal completeNumber = combineChunks(chunks); return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1)).toString() : completeNumber.toString(); } private static boolean isValidConjunction(boolean prevNumWasHundred, boolean prevNumWasPowerOfTen, ArrayDeque wordDeque) { - if (wordDeque.isEmpty()) return false; + if (wordDeque.isEmpty()) { + return false; + } String nextWord = wordDeque.pollFirst(); String afterNextWord = wordDeque.peekFirst(); @@ -165,18 +197,22 @@ private static boolean isAdditionSafe(BigDecimal currentChunk, BigDecimal number return chunkDigitCount > numberDigitCount; } - private static String convertDecimalPart(Queue wordDeque) { + private static String convertDecimalPart(ArrayDeque wordDeque) { StringBuilder decimalPart = new StringBuilder("."); while (!wordDeque.isEmpty()) { String word = wordDeque.poll(); Integer number = NUMBER_MAP.getOrDefault(word, null); - if (number != null) + if (number != null) { decimalPart.append(number); - else + } + else { return "Invalid Input. Unexpected Word (after Point): " + word; + } } - if (decimalPart.length() == 1) return "Invalid Input. Decimal Part is missing Numbers."; + if (decimalPart.length() == 1) { + return "Invalid Input. Decimal Part is missing Numbers."; + } return decimalPart.toString(); } @@ -188,7 +224,9 @@ private static BigDecimal combineChunks(List chunks) { public static BigDecimal convertToBigDecimal(String numberInWords) { String conversionResult = convert(numberInWords); - if (conversionResult.startsWith("I")) return null; + if (conversionResult.startsWith("I")) { + return null; + } return new BigDecimal(conversionResult); } } diff --git a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java index 380ab562c370..4b0cc6115e62 100644 --- a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java +++ b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java @@ -1,6 +1,7 @@ package com.thealgorithms.conversions; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import java.math.BigDecimal; import org.junit.jupiter.api.Test; From 2f89b98c178f6b171379d57d130894c8be399b7e Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 09:08:53 +0530 Subject: [PATCH 06/15] solve build error, fix checkstyle and clang-format --- .../conversions/WordsToNumber.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index e984b8e7a101..4037954c2e19 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.List; - /** A Java-based utility for converting English word representations of numbers into their numeric form. This utility supports whole numbers, decimals, @@ -112,8 +111,7 @@ public static String convert(String numberInWords) { if (chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk)) { chunks.add(nextChunk); - } - else { + } else { return "Invalid Input. Unexpected Word: " + word; } currentChunk = BigDecimal.ZERO; @@ -131,8 +129,7 @@ public static String convert(String numberInWords) { if (currentChunkIsZero || isAdditionSafe(currentChunk, bigDecimalNumber)) { currentChunk = currentChunk.add(bigDecimalNumber); - } - else { + } else { return "Invalid Input. Unexpected Word: " + word; } continue; @@ -147,8 +144,7 @@ public static String convert(String numberInWords) { String decimalPart = convertDecimalPart(wordDeque); if (!decimalPart.startsWith("I")) { chunks.add(new BigDecimal(decimalPart)); - } - else { + } else { return decimalPart; } break; @@ -204,8 +200,7 @@ private static String convertDecimalPart(ArrayDeque wordDeque) { Integer number = NUMBER_MAP.getOrDefault(word, null); if (number != null) { decimalPart.append(number); - } - else { + } else { return "Invalid Input. Unexpected Word (after Point): " + word; } } @@ -218,7 +213,9 @@ private static String convertDecimalPart(ArrayDeque wordDeque) { private static BigDecimal combineChunks(List chunks) { BigDecimal completeNumber = BigDecimal.ZERO; - for (BigDecimal chunk : chunks) completeNumber = completeNumber.add(chunk); + for (BigDecimal chunk : chunks) { + completeNumber = completeNumber.add(chunk); + } return completeNumber; } From 0b591399dc7726a297926624d7944d3eb49a8cac Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 09:18:17 +0530 Subject: [PATCH 07/15] solve build error, fix 'BigDecimal.equals()' spot bug --- .../java/com/thealgorithms/conversions/WordsToNumber.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 4037954c2e19..3e123308d9f7 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -81,7 +81,7 @@ public static String convert(String numberInWords) { while (!wordDeque.isEmpty()) { String word = wordDeque.poll(); - boolean currentChunkIsZero = currentChunk.equals(BigDecimal.ZERO); + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; boolean isConjunction = word.equals("and"); if (isConjunction && isValidConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque)) { @@ -161,7 +161,7 @@ public static String convert(String numberInWords) { return "Invalid Input. " + (isConjunction ? "Unexpected 'and' placement" : "Unknown Word: " + word); } - if (!currentChunk.equals(BigDecimal.ZERO)) { + if (!(currentChunk.compareTo(BigDecimal.ZERO) == 0)) { chunks.add(currentChunk); } BigDecimal completeNumber = combineChunks(chunks); From 00c709ed9548f435da4a417989c951c2a211d298 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:58:20 +0530 Subject: [PATCH 08/15] solve build error, resolve PMD Warning --- .../conversions/WordsToNumber.java | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 3e123308d9f7..22c5cde70ba4 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -79,7 +79,9 @@ public static String convert(String numberInWords) { boolean prevNumWasHundred = false; boolean prevNumWasPowerOfTen = false; - while (!wordDeque.isEmpty()) { + String errorMessage = null; + + while (!wordDeque.isEmpty() && errorMessage == null) { String word = wordDeque.poll(); boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; @@ -88,10 +90,10 @@ public static String convert(String numberInWords) { continue; } - boolean isHundred = word.equals("hundred"); - if (isHundred) { + if (word.equals("hundred")) { if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) { - return "Invalid Input. Unexpected Word: " + word; + errorMessage = "Invalid Input. Unexpected Word: " + word; + continue; } if (currentChunkIsZero) { currentChunk = currentChunk.add(BigDecimal.ONE); @@ -105,15 +107,16 @@ public static String convert(String numberInWords) { BigDecimal powerOfTen = POWERS_OF_TEN.getOrDefault(word, null); if (powerOfTen != null) { if (currentChunkIsZero || prevNumWasPowerOfTen) { - return "Invalid Input. Unexpected Word: " + word; + errorMessage = "Invalid Input. Unexpected Word: " + word; + continue; } BigDecimal nextChunk = currentChunk.multiply(powerOfTen); - if (chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk)) { - chunks.add(nextChunk); - } else { - return "Invalid Input. Unexpected Word: " + word; + if (!(chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk))) { + errorMessage = "Invalid Input. Unexpected Word: " + word; + continue; } + chunks.add(nextChunk); currentChunk = BigDecimal.ZERO; prevNumWasPowerOfTen = true; continue; @@ -123,14 +126,15 @@ public static String convert(String numberInWords) { Integer number = NUMBER_MAP.getOrDefault(word, null); if (number != null) { if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) { - return "Invalid Input. Unexpected Word: " + word; + errorMessage = "Invalid Input. Unexpected Word: " + word; + continue; } BigDecimal bigDecimalNumber = BigDecimal.valueOf(number); if (currentChunkIsZero || isAdditionSafe(currentChunk, bigDecimalNumber)) { currentChunk = currentChunk.add(bigDecimalNumber); } else { - return "Invalid Input. Unexpected Word: " + word; + errorMessage = "Invalid Input. Unexpected Word: " + word; } continue; } @@ -145,20 +149,25 @@ public static String convert(String numberInWords) { if (!decimalPart.startsWith("I")) { chunks.add(new BigDecimal(decimalPart)); } else { - return decimalPart; + errorMessage = decimalPart; } - break; + continue; } if (word.equals("negative")) { if (isNegative) { - return "Invalid Input. Multiple 'Negative's detected."; + errorMessage = "Invalid Input. Multiple 'Negative's detected."; + } else { + isNegative = chunks.isEmpty() && currentChunkIsZero; } - isNegative = chunks.isEmpty() && currentChunkIsZero; continue; } - return "Invalid Input. " + (isConjunction ? "Unexpected 'and' placement" : "Unknown Word: " + word); + errorMessage = "Invalid Input. " + (isConjunction ? "Unexpected 'and' placement" : "Unknown Word: " + word); + } + + if (errorMessage != null) { + return errorMessage; } if (!(currentChunk.compareTo(BigDecimal.ZERO) == 0)) { @@ -195,14 +204,20 @@ private static boolean isAdditionSafe(BigDecimal currentChunk, BigDecimal number private static String convertDecimalPart(ArrayDeque wordDeque) { StringBuilder decimalPart = new StringBuilder("."); + String errorMessage = null; + while (!wordDeque.isEmpty()) { String word = wordDeque.poll(); Integer number = NUMBER_MAP.getOrDefault(word, null); - if (number != null) { - decimalPart.append(number); - } else { - return "Invalid Input. Unexpected Word (after Point): " + word; + if (number == null) { + errorMessage = "Invalid Input. Unexpected Word (after Point): " + word; + break; } + decimalPart.append(number); + } + + if (errorMessage != null) { + return errorMessage; } if (decimalPart.length() == 1) { From 3dc52a40e5a4a19bdc98d43bcdb5995cfa97401f Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Sat, 15 Mar 2025 04:19:21 +0530 Subject: [PATCH 09/15] try to solve cyclomatic complexity issue --- .../conversions/WordsToNumber.java | 305 ++++++++++-------- .../conversions/WordsToNumberTest.java | 46 ++- 2 files changed, 216 insertions(+), 135 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 22c5cde70ba4..8ec7a0dcaf79 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; /** A Java-based utility for converting English word representations of numbers @@ -16,11 +17,12 @@ */ public final class WordsToNumber { + private WordsToNumber() { } - private static final HashMap NUMBER_MAP = new HashMap<>(); - private static final HashMap POWERS_OF_TEN = new HashMap<>(); + private static final Map NUMBER_MAP = new HashMap<>(); + private static final Map POWERS_OF_TEN = new HashMap<>(); static { NUMBER_MAP.put("zero", 0); @@ -60,9 +62,21 @@ private WordsToNumber() { public static String convert(String numberInWords) { if (numberInWords == null) { - return "Null Input"; + throw new WordsToNumberException(WordsToNumberException.ErrorType.NULL_INPUT, ""); } + ArrayDeque wordDeque = preprocessWords(numberInWords); + BigDecimal completeNumber = convertWordQueueToBigDecimal(wordDeque); + + return completeNumber.toString(); + } + + public static BigDecimal convertToBigDecimal(String numberInWords) { + String conversionResult = convert(numberInWords); + return new BigDecimal(conversionResult); + } + + private static ArrayDeque preprocessWords(String numberInWords) { String[] wordSplitArray = numberInWords.trim().split("[ ,-]"); ArrayDeque wordDeque = new ArrayDeque<>(); for (String word : wordSplitArray) { @@ -71,52 +85,115 @@ public static String convert(String numberInWords) { } wordDeque.add(word.toLowerCase()); } + if (wordDeque.isEmpty()) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.NULL_INPUT, ""); + } + return wordDeque; + } - List chunks = new ArrayList<>(); + private static void handleConjunction(boolean prevNumWasHundred, boolean prevNumWasPowerOfTen, ArrayDeque wordDeque) { + if (wordDeque.isEmpty()) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, ""); + } + + String nextWord = wordDeque.pollFirst(); + String afterNextWord = wordDeque.peekFirst(); + + wordDeque.addFirst(nextWord); + + Integer number = NUMBER_MAP.getOrDefault(nextWord, null); + + boolean isPrevWordValid = prevNumWasHundred || prevNumWasPowerOfTen; + boolean isNextWordValid = number != null && (number >= 10 || afterNextWord == null || "point".equals(afterNextWord)); + + if (!isPrevWordValid || !isNextWordValid) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, ""); + } + } + + private static BigDecimal handleHundred(BigDecimal currentChunk, String word, boolean prevNumWasPowerOfTen) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + if (currentChunkIsZero) { + currentChunk = currentChunk.add(BigDecimal.ONE); + } + return currentChunk.multiply(BigDecimal.valueOf(100)); + } + + private static void handlePowerOfTen(List chunks, BigDecimal currentChunk, BigDecimal powerOfTen, String word, boolean prevNumWasPowerOfTen) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (currentChunkIsZero || prevNumWasPowerOfTen) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + BigDecimal nextChunk = currentChunk.multiply(powerOfTen); + + if (!(chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk))) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + chunks.add(nextChunk); + } + + private static BigDecimal handleNumber(List chunks, BigDecimal currentChunk, String word, Integer number) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + BigDecimal bigDecimalNumber = BigDecimal.valueOf(number); + + if (!currentChunkIsZero && !isAdditionSafe(currentChunk, bigDecimalNumber)) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + return currentChunk.add(bigDecimalNumber); + } + + private static void handlePoint(List chunks, BigDecimal currentChunk, ArrayDeque wordDeque) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (!currentChunkIsZero) { + chunks.add(currentChunk); + } + + String decimalPart = convertDecimalPart(wordDeque); + chunks.add(new BigDecimal(decimalPart)); + } + + private static void handleNegative(boolean isNegative) { + if (isNegative) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.MULTIPLE_NEGATIVES, ""); + } + throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_NEGATIVE, ""); + } + + private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDeque) { BigDecimal currentChunk = BigDecimal.ZERO; + List chunks = new ArrayList<>(); + + boolean isNegative = "negative".equals(wordDeque.peek()); + if (isNegative) wordDeque.poll(); - boolean isNegative = false; boolean prevNumWasHundred = false; boolean prevNumWasPowerOfTen = false; - String errorMessage = null; - - while (!wordDeque.isEmpty() && errorMessage == null) { + while (!wordDeque.isEmpty()) { String word = wordDeque.poll(); - boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; - boolean isConjunction = word.equals("and"); - if (isConjunction && isValidConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque)) { - continue; - } - - if (word.equals("hundred")) { - if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) { - errorMessage = "Invalid Input. Unexpected Word: " + word; + switch (word) { + case "and" -> { + handleConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque); continue; } - if (currentChunkIsZero) { - currentChunk = currentChunk.add(BigDecimal.ONE); + case "hundred" -> { + currentChunk = handleHundred(currentChunk, word, prevNumWasPowerOfTen); + prevNumWasHundred = true; + continue; } - currentChunk = currentChunk.multiply(BigDecimal.valueOf(100)); - prevNumWasHundred = true; - continue; } prevNumWasHundred = false; BigDecimal powerOfTen = POWERS_OF_TEN.getOrDefault(word, null); if (powerOfTen != null) { - if (currentChunkIsZero || prevNumWasPowerOfTen) { - errorMessage = "Invalid Input. Unexpected Word: " + word; - continue; - } - BigDecimal nextChunk = currentChunk.multiply(powerOfTen); - - if (!(chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk))) { - errorMessage = "Invalid Input. Unexpected Word: " + word; - continue; - } - chunks.add(nextChunk); + handlePowerOfTen(chunks, currentChunk, powerOfTen, word, prevNumWasPowerOfTen); currentChunk = BigDecimal.ZERO; prevNumWasPowerOfTen = true; continue; @@ -125,120 +202,96 @@ public static String convert(String numberInWords) { Integer number = NUMBER_MAP.getOrDefault(word, null); if (number != null) { - if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) { - errorMessage = "Invalid Input. Unexpected Word: " + word; - continue; - } - BigDecimal bigDecimalNumber = BigDecimal.valueOf(number); - - if (currentChunkIsZero || isAdditionSafe(currentChunk, bigDecimalNumber)) { - currentChunk = currentChunk.add(bigDecimalNumber); - } else { - errorMessage = "Invalid Input. Unexpected Word: " + word; - } + currentChunk = handleNumber(chunks, currentChunk, word, number); continue; } - if (word.equals("point")) { - if (!currentChunkIsZero) { - chunks.add(currentChunk); - } - currentChunk = BigDecimal.ZERO; - - String decimalPart = convertDecimalPart(wordDeque); - if (!decimalPart.startsWith("I")) { - chunks.add(new BigDecimal(decimalPart)); - } else { - errorMessage = decimalPart; - } - continue; - } - - if (word.equals("negative")) { - if (isNegative) { - errorMessage = "Invalid Input. Multiple 'Negative's detected."; - } else { - isNegative = chunks.isEmpty() && currentChunkIsZero; + switch (word) { + case "point" -> { + handlePoint(chunks, currentChunk, wordDeque); + currentChunk = BigDecimal.ZERO; + continue; } - continue; + case "negative" -> handleNegative(isNegative); } - errorMessage = "Invalid Input. " + (isConjunction ? "Unexpected 'and' placement" : "Unknown Word: " + word); + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNKNOWN_WORD, word); } - if (errorMessage != null) { - return errorMessage; - } - - if (!(currentChunk.compareTo(BigDecimal.ZERO) == 0)) { + if (currentChunk.compareTo(BigDecimal.ZERO) != 0) { chunks.add(currentChunk); } - BigDecimal completeNumber = combineChunks(chunks); - return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1)).toString() : completeNumber.toString(); - } - - private static boolean isValidConjunction(boolean prevNumWasHundred, boolean prevNumWasPowerOfTen, ArrayDeque wordDeque) { - if (wordDeque.isEmpty()) { - return false; - } + BigDecimal completeNumber = combineChunks(chunks); + return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1)) : + completeNumber; + } - String nextWord = wordDeque.pollFirst(); - String afterNextWord = wordDeque.peekFirst(); + private static boolean isAdditionSafe(BigDecimal currentChunk, BigDecimal number) { + int chunkDigitCount = currentChunk.toString().length(); + int numberDigitCount = number.toString().length(); + return chunkDigitCount > numberDigitCount; + } - wordDeque.addFirst(nextWord); + private static String convertDecimalPart(ArrayDeque wordDeque) { + StringBuilder decimalPart = new StringBuilder("."); + + while (!wordDeque.isEmpty()) { + String word = wordDeque.poll(); + Integer number = NUMBER_MAP.getOrDefault(word, null); + if (number == null) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD_AFTER_POINT, word); + } + decimalPart.append(number); + } + + boolean missingNumbers = decimalPart.length() == 1; + if (missingNumbers) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.MISSING_DECIMAL_NUMBERS, ""); + } + return decimalPart.toString(); + } - Integer number = NUMBER_MAP.getOrDefault(nextWord, null); + private static BigDecimal combineChunks(List chunks) { + BigDecimal completeNumber = BigDecimal.ZERO; + for (BigDecimal chunk : chunks) { + completeNumber = completeNumber.add(chunk); + } + return completeNumber; + } + } - boolean isPrevWordValid = prevNumWasHundred || prevNumWasPowerOfTen; - boolean isNextWordValid = number != null && (number >= 10 || afterNextWord == null || afterNextWord.equals("point")); + class WordsToNumberException extends RuntimeException { - return isPrevWordValid && isNextWordValid; - } + enum ErrorType { + NULL_INPUT("'null' or empty input provided"), + UNKNOWN_WORD("Unknown Word: "), + UNEXPECTED_WORD("Unexpected Word: "), + UNEXPECTED_WORD_AFTER_POINT("Unexpected Word (after Point): "), + MISSING_DECIMAL_NUMBERS("Decimal part is missing numbers."), + MULTIPLE_NEGATIVES("Multiple 'Negative's detected."), + INVALID_NEGATIVE("Incorrect 'negative' placement"), + INVALID_CONJUNCTION("Incorrect 'and' placement"); - private static boolean isAdditionSafe(BigDecimal currentChunk, BigDecimal number) { - int chunkDigitCount = currentChunk.toString().length(); - int numberDigitCount = number.toString().length(); - return chunkDigitCount > numberDigitCount; - } + private final String message; - private static String convertDecimalPart(ArrayDeque wordDeque) { - StringBuilder decimalPart = new StringBuilder("."); - String errorMessage = null; + ErrorType(String message) { + this.message = message; + } - while (!wordDeque.isEmpty()) { - String word = wordDeque.poll(); - Integer number = NUMBER_MAP.getOrDefault(word, null); - if (number == null) { - errorMessage = "Invalid Input. Unexpected Word (after Point): " + word; - break; + public String formatMessage(String details) { + return "Invalid Input. " + message + (details.isEmpty() ? "" : details); + } } - decimalPart.append(number); - } - if (errorMessage != null) { - return errorMessage; - } + public final ErrorType errorType; - if (decimalPart.length() == 1) { - return "Invalid Input. Decimal Part is missing Numbers."; - } - return decimalPart.toString(); - } - - private static BigDecimal combineChunks(List chunks) { - BigDecimal completeNumber = BigDecimal.ZERO; - for (BigDecimal chunk : chunks) { - completeNumber = completeNumber.add(chunk); - } - return completeNumber; - } + WordsToNumberException(ErrorType errorType, String details) { + super(errorType.formatMessage(details)); + this.errorType = errorType; + } - public static BigDecimal convertToBigDecimal(String numberInWords) { - String conversionResult = convert(numberInWords); - if (conversionResult.startsWith("I")) { - return null; + public ErrorType getErrorType() { + return errorType; + } } - return new BigDecimal(conversionResult); - } -} diff --git a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java index 4b0cc6115e62..544cc494c780 100644 --- a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java +++ b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.math.BigDecimal; import org.junit.jupiter.api.Test; @@ -10,7 +11,8 @@ public class WordsToNumberTest { @Test void testNullInput() { - assertEquals("Null Input", WordsToNumber.convert(null), "Null input should return 'Null Input'"); + WordsToNumberException exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert(null)); + assertEquals(WordsToNumberException.ErrorType.NULL_INPUT, exception.getErrorType(), "Exception should be of type NULL_INPUT"); } @Test @@ -70,18 +72,44 @@ void testCaseInsensitivity() { @Test void testInvalidInputs() { - assertEquals("Invalid Input. Unknown Word: alpha", WordsToNumber.convert("negative one hundred AlPha"), "'AlPha' is not a valid word"); - assertEquals("Invalid Input. Unexpected Word: thirteen", WordsToNumber.convert("twenty thirteen"), "'twenty thirteen' is not a valid format"); - assertEquals("Invalid Input. Multiple 'Negative's detected.", WordsToNumber.convert("negative negative ten"), "Should detect multiple negatives"); - assertEquals("Invalid Input. Unexpected Word: hundred", WordsToNumber.convert("one hundred hundred"), "Direct repetition of 'hundred' is invalid"); - assertEquals("Invalid Input. Unexpected 'and' placement", WordsToNumber.convert("one thousand and hundred"), "Detects invalid 'and' placement"); - assertEquals("Invalid Input. Unexpected Word: hundred", WordsToNumber.convert("one thousand hundred"), "Detects incorrect placement of powers of ten"); - assertEquals("Invalid Input. Unexpected 'and' placement", WordsToNumber.convert("nine hundred and nine hundred"), "Detects invalid 'and' placement"); + WordsToNumberException exception; + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("negative one hundred AlPha")); + assertEquals(WordsToNumberException.ErrorType.UNKNOWN_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("twenty thirteen")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("negative negative ten")); + assertEquals(WordsToNumberException.ErrorType.MULTIPLE_NEGATIVES, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one hundred hundred")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one thousand and hundred")); + assertEquals(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one thousand hundred")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("nine hundred and nine hundred")); + assertEquals(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("forty two point")); + assertEquals(WordsToNumberException.ErrorType.MISSING_DECIMAL_NUMBERS, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("sixty seven point hello")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD_AFTER_POINT, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one negative")); + assertEquals(WordsToNumberException.ErrorType.INVALID_NEGATIVE, exception.getErrorType()); } @Test void testConvertToBigDecimal() { assertEquals(new BigDecimal("-100000000000000.056"), WordsToNumber.convertToBigDecimal("negative one hundred trillion point zero five six"), "should convert to appropriate BigDecimal value"); - assertNull(WordsToNumber.convertToBigDecimal("invalid input"), "Invalid input should return null"); + + WordsToNumberException exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convertToBigDecimal(null)); + assertEquals(WordsToNumberException.ErrorType.NULL_INPUT, exception.getErrorType(), "Exception should be of type NULL_INPUT"); } } From 2773fc1ceb963407a0f40398471903642b6bc396 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:12:45 +0530 Subject: [PATCH 10/15] try to solve clang-format errors and add serialVersionID --- .../conversions/WordsToNumber.java | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 8ec7a0dcaf79..67a0032f9300 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -1,5 +1,6 @@ package com.thealgorithms.conversions; +import java.io.Serial; import java.math.BigDecimal; import java.util.ArrayDeque; import java.util.ArrayList; @@ -263,35 +264,37 @@ private static BigDecimal combineChunks(List chunks) { class WordsToNumberException extends RuntimeException { - enum ErrorType { - NULL_INPUT("'null' or empty input provided"), - UNKNOWN_WORD("Unknown Word: "), - UNEXPECTED_WORD("Unexpected Word: "), - UNEXPECTED_WORD_AFTER_POINT("Unexpected Word (after Point): "), - MISSING_DECIMAL_NUMBERS("Decimal part is missing numbers."), - MULTIPLE_NEGATIVES("Multiple 'Negative's detected."), - INVALID_NEGATIVE("Incorrect 'negative' placement"), - INVALID_CONJUNCTION("Incorrect 'and' placement"); + @Serial private static final long serialVersionUID = 1L; - private final String message; + enum ErrorType { + NULL_INPUT("'null' or empty input provided"), + UNKNOWN_WORD("Unknown Word: "), + UNEXPECTED_WORD("Unexpected Word: "), + UNEXPECTED_WORD_AFTER_POINT("Unexpected Word (after Point): "), + MISSING_DECIMAL_NUMBERS("Decimal part is missing numbers."), + MULTIPLE_NEGATIVES("Multiple 'Negative's detected."), + INVALID_NEGATIVE("Incorrect 'negative' placement"), + INVALID_CONJUNCTION("Incorrect 'and' placement"); - ErrorType(String message) { - this.message = message; - } + private final String message; + + ErrorType(String message) { + this.message = message; + } - public String formatMessage(String details) { - return "Invalid Input. " + message + (details.isEmpty() ? "" : details); + public String formatMessage(String details) { + return "Invalid Input. " + message + (details.isEmpty() ? "" : details); + } } - } - public final ErrorType errorType; + public final ErrorType errorType; - WordsToNumberException(ErrorType errorType, String details) { - super(errorType.formatMessage(details)); - this.errorType = errorType; - } + WordsToNumberException(ErrorType errorType, String details) { + super(errorType.formatMessage(details)); + this.errorType = errorType; + } - public ErrorType getErrorType() { - return errorType; - } + public ErrorType getErrorType() { + return errorType; + } } From 24c9da87f239650073a49ce80c2613bb1da7d8c0 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:30:23 +0530 Subject: [PATCH 11/15] fix checkstyle issues --- .../conversions/WordsToNumber.java | 17 ++++++++++++++--- .../conversions/WordsToNumberTest.java | 1 - 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 67a0032f9300..36d4b8b4ec18 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -171,7 +171,9 @@ private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDe List chunks = new ArrayList<>(); boolean isNegative = "negative".equals(wordDeque.peek()); - if (isNegative) wordDeque.poll(); + if (isNegative) { + wordDeque.poll(); + } boolean prevNumWasHundred = false; boolean prevNumWasPowerOfTen = false; @@ -189,6 +191,9 @@ private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDe prevNumWasHundred = true; continue; } + default -> { + + } } prevNumWasHundred = false; @@ -213,7 +218,12 @@ private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDe currentChunk = BigDecimal.ZERO; continue; } - case "negative" -> handleNegative(isNegative); + case "negative" -> { + handleNegative(isNegative); + } + default -> { + + } } throw new WordsToNumberException(WordsToNumberException.ErrorType.UNKNOWN_WORD, word); @@ -224,7 +234,8 @@ private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDe } BigDecimal completeNumber = combineChunks(chunks); - return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1)) : + return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1)) + : completeNumber; } diff --git a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java index 544cc494c780..fbf63e37946b 100644 --- a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java +++ b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java @@ -1,7 +1,6 @@ package com.thealgorithms.conversions; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.math.BigDecimal; From 75e34d2a2e4b4a3f3fe1a8439f0efa8758efa5e2 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:40:17 +0530 Subject: [PATCH 12/15] try to fix build error, overly concrete parameter --- .../java/com/thealgorithms/conversions/WordsToNumber.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 36d4b8b4ec18..7768d2912ff2 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -123,7 +124,7 @@ private static BigDecimal handleHundred(BigDecimal currentChunk, String word, bo return currentChunk.multiply(BigDecimal.valueOf(100)); } - private static void handlePowerOfTen(List chunks, BigDecimal currentChunk, BigDecimal powerOfTen, String word, boolean prevNumWasPowerOfTen) { + private static void handlePowerOfTen(Collection chunks, BigDecimal currentChunk, BigDecimal powerOfTen, String word, boolean prevNumWasPowerOfTen) { boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; if (currentChunkIsZero || prevNumWasPowerOfTen) { throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); @@ -136,7 +137,7 @@ private static void handlePowerOfTen(List chunks, BigDecimal current chunks.add(nextChunk); } - private static BigDecimal handleNumber(List chunks, BigDecimal currentChunk, String word, Integer number) { + private static BigDecimal handleNumber(Collection chunks, BigDecimal currentChunk, String word, Integer number) { boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) { throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); From 1b752d5d1d39ece406b31e5bbe6af9fd08365644 Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:45:21 +0530 Subject: [PATCH 13/15] fix mistake in build error solution --- .../java/com/thealgorithms/conversions/WordsToNumber.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 7768d2912ff2..0e04ba224692 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -124,7 +124,7 @@ private static BigDecimal handleHundred(BigDecimal currentChunk, String word, bo return currentChunk.multiply(BigDecimal.valueOf(100)); } - private static void handlePowerOfTen(Collection chunks, BigDecimal currentChunk, BigDecimal powerOfTen, String word, boolean prevNumWasPowerOfTen) { + private static void handlePowerOfTen(List chunks, BigDecimal currentChunk, BigDecimal powerOfTen, String word, boolean prevNumWasPowerOfTen) { boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; if (currentChunkIsZero || prevNumWasPowerOfTen) { throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); @@ -150,7 +150,7 @@ private static BigDecimal handleNumber(Collection chunks, BigDecimal return currentChunk.add(bigDecimalNumber); } - private static void handlePoint(List chunks, BigDecimal currentChunk, ArrayDeque wordDeque) { + private static void handlePoint(Collection chunks, BigDecimal currentChunk, ArrayDeque wordDeque) { boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; if (!currentChunkIsZero) { chunks.add(currentChunk); From 33201ba4380c5ddaa1f483d9e12b83dbab16a58c Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:27:40 +0530 Subject: [PATCH 14/15] replace hashmaps with enums for better code organisation --- .../conversions/WordsToNumber.java | 117 +++++++++++------- 1 file changed, 74 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 0e04ba224692..5fa58a47c8fd 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -5,9 +5,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** A Java-based utility for converting English word representations of numbers @@ -23,43 +21,76 @@ public final class WordsToNumber { private WordsToNumber() { } - private static final Map NUMBER_MAP = new HashMap<>(); - private static final Map POWERS_OF_TEN = new HashMap<>(); - - static { - NUMBER_MAP.put("zero", 0); - NUMBER_MAP.put("one", 1); - NUMBER_MAP.put("two", 2); - NUMBER_MAP.put("three", 3); - NUMBER_MAP.put("four", 4); - NUMBER_MAP.put("five", 5); - NUMBER_MAP.put("six", 6); - NUMBER_MAP.put("seven", 7); - NUMBER_MAP.put("eight", 8); - NUMBER_MAP.put("nine", 9); - NUMBER_MAP.put("ten", 10); - NUMBER_MAP.put("eleven", 11); - NUMBER_MAP.put("twelve", 12); - NUMBER_MAP.put("thirteen", 13); - NUMBER_MAP.put("fourteen", 14); - NUMBER_MAP.put("fifteen", 15); - NUMBER_MAP.put("sixteen", 16); - NUMBER_MAP.put("seventeen", 17); - NUMBER_MAP.put("eighteen", 18); - NUMBER_MAP.put("nineteen", 19); - NUMBER_MAP.put("twenty", 20); - NUMBER_MAP.put("thirty", 30); - NUMBER_MAP.put("forty", 40); - NUMBER_MAP.put("fifty", 50); - NUMBER_MAP.put("sixty", 60); - NUMBER_MAP.put("seventy", 70); - NUMBER_MAP.put("eighty", 80); - NUMBER_MAP.put("ninety", 90); - - POWERS_OF_TEN.put("thousand", new BigDecimal("1000")); - POWERS_OF_TEN.put("million", new BigDecimal("1000000")); - POWERS_OF_TEN.put("billion", new BigDecimal("1000000000")); - POWERS_OF_TEN.put("trillion", new BigDecimal("1000000000000")); + private enum NumberWord { + ZERO("zero", 0), + ONE("one", 1), + TWO("two", 2), + THREE("three", 3), + FOUR("four", 4), + FIVE("five", 5), + SIX("six", 6), + SEVEN("seven", 7), + EIGHT("eight", 8), + NINE("nine", 9), + TEN("ten", 10), + ELEVEN("eleven", 11), + TWELVE("twelve", 12), + THIRTEEN("thirteen", 13), + FOURTEEN("fourteen", 14), + FIFTEEN("fifteen", 15), + SIXTEEN("sixteen", 16), + SEVENTEEN("seventeen", 17), + EIGHTEEN("eighteen", 18), + NINETEEN("nineteen", 19), + TWENTY("twenty", 20), + THIRTY("thirty", 30), + FORTY("forty", 40), + FIFTY("fifty", 50), + SIXTY("sixty", 60), + SEVENTY("seventy", 70), + EIGHTY("eighty", 80), + NINETY("ninety", 90); + + private final String word; + private final int value; + + NumberWord(String word, int value) { + this.word = word; + this.value = value; + } + + public static Integer getValue(String word) { + for (NumberWord num : NumberWord.values()) { + if (word.equals(num.word)) { + return num.value; + } + } + return null; + } + } + + private enum PowerOfTen { + THOUSAND("thousand", new BigDecimal("1000")), + MILLION("million", new BigDecimal("1000000")), + BILLION("billion", new BigDecimal("1000000000")), + TRILLION("trillion", new BigDecimal("1000000000000")); + + private final String word; + private final BigDecimal value; + + PowerOfTen(String word, BigDecimal value) { + this.word = word; + this.value = value; + } + + public static BigDecimal getValue(String word) { + for (PowerOfTen power : PowerOfTen.values()) { + if (word.equals(power.word)) { + return power.value; + } + } + return null; + } } public static String convert(String numberInWords) { @@ -103,7 +134,7 @@ private static void handleConjunction(boolean prevNumWasHundred, boolean prevNum wordDeque.addFirst(nextWord); - Integer number = NUMBER_MAP.getOrDefault(nextWord, null); + Integer number = NumberWord.getValue(nextWord); boolean isPrevWordValid = prevNumWasHundred || prevNumWasPowerOfTen; boolean isNextWordValid = number != null && (number >= 10 || afterNextWord == null || "point".equals(afterNextWord)); @@ -198,7 +229,7 @@ private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDe } prevNumWasHundred = false; - BigDecimal powerOfTen = POWERS_OF_TEN.getOrDefault(word, null); + BigDecimal powerOfTen = PowerOfTen.getValue(word); if (powerOfTen != null) { handlePowerOfTen(chunks, currentChunk, powerOfTen, word, prevNumWasPowerOfTen); currentChunk = BigDecimal.ZERO; @@ -207,7 +238,7 @@ private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDe } prevNumWasPowerOfTen = false; - Integer number = NUMBER_MAP.getOrDefault(word, null); + Integer number = NumberWord.getValue(word); if (number != null) { currentChunk = handleNumber(chunks, currentChunk, word, number); continue; @@ -251,7 +282,7 @@ private static String convertDecimalPart(ArrayDeque wordDeque) { while (!wordDeque.isEmpty()) { String word = wordDeque.poll(); - Integer number = NUMBER_MAP.getOrDefault(word, null); + Integer number = NumberWord.getValue(word); if (number == null) { throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD_AFTER_POINT, word); } From aa82d5ca2d16bba3cc2eb6a698c57a86838404bb Mon Sep 17 00:00:00 2001 From: Sufiyan Chougule <100443252+Sufi-san@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:33:38 +0530 Subject: [PATCH 15/15] fix unnecessary qualifier problem --- .../java/com/thealgorithms/conversions/WordsToNumber.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java index 5fa58a47c8fd..e2b81a0f4b47 100644 --- a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -60,7 +60,7 @@ private enum NumberWord { } public static Integer getValue(String word) { - for (NumberWord num : NumberWord.values()) { + for (NumberWord num : values()) { if (word.equals(num.word)) { return num.value; } @@ -84,7 +84,7 @@ private enum PowerOfTen { } public static BigDecimal getValue(String word) { - for (PowerOfTen power : PowerOfTen.values()) { + for (PowerOfTen power : values()) { if (word.equals(power.word)) { return power.value; }