From 6e747214d77b98df4fa191e99e882533cc5616f2 Mon Sep 17 00:00:00 2001 From: Jeffinson Darmawan Date: Sun, 31 Mar 2024 02:19:18 +0800 Subject: [PATCH 1/2] Add Damerau-Levenshtein distance and fixed a bug on parser --- src/main/java/florizz/core/FuzzyLogic.java | 36 ++++++++++------- src/main/java/florizz/core/Parser.java | 47 ++++++++++++++++------ 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/main/java/florizz/core/FuzzyLogic.java b/src/main/java/florizz/core/FuzzyLogic.java index 55658350b9..792c9d7fb9 100644 --- a/src/main/java/florizz/core/FuzzyLogic.java +++ b/src/main/java/florizz/core/FuzzyLogic.java @@ -57,11 +57,11 @@ public static String detectItem(String userInput) throws FlorizzException { Ui uiFuzzy = new Ui(); // Iterate over predefined commands - for (String command : ITEMS.keySet()) { - int distance = computeLevenshteinDistance(command, userInput); + for (String item : ITEMS.keySet()) { + int distance = computeDLDistance(item, userInput); if (distance < bestDistance) { bestDistance = distance; - bestMatch = command; + bestMatch = item; } } @@ -79,19 +79,19 @@ public static String detectItem(String userInput) throws FlorizzException { } /** - * Computes the Levenshtein distance which is a metric used to measure the similarity between two strings. + * Computes the Damerau-Levenshtein distance which is a metric used to measure the similarity between two strings. * It calculates the minimum number of single-character edits required to change one string into another. - * These edits can be insertions, deletions, or substitutions of individual characters. + * These edits can be insertions, deletions, substitutions and transpositions of individual characters. * - * @param s1 The first string. - * @param s2 The second string. - * @return The Levenshtein distance between the two strings. + * @param item The first string. + * @param userInput The second string. + * @return The Damerau-Levenshtein distance between the two strings. */ - private static int computeLevenshteinDistance(String s1, String s2) { - assert s1 != null && s2 != null : "Strings cannot be null"; + private static int computeDLDistance(String item, String userInput) { + assert item != null && userInput != null : "Strings cannot be null"; - int m = s1.length(); - int n = s2.length(); + int m = item.length(); + int n = userInput.length(); int[] previousRow = new int[n + 1]; int[] currentRow = new int[n + 1]; @@ -101,16 +101,22 @@ private static int computeLevenshteinDistance(String s1, String s2) { previousRow[j] = j; } - // Calculate the Levenshtein distance + // Calculate the Damerau-Levenshtein distance for (int i = 1; i <= m; i++) { currentRow[0] = i; for (int j = 1; j <= n; j++) { - int substitutionCost = (s1.charAt(i - 1) == s2.charAt(j - 1)) ? 0 : 1; + int substitutionCost = (item.charAt(i - 1) == userInput.charAt(j - 1)) ? 0 : 1; currentRow[j] = Math.min(Math.min( previousRow[j] + 1, // deletion currentRow[j - 1] + 1), // insertion previousRow[j - 1] + substitutionCost); // substitution + + // Check for transpositions + if (i > 1 && j > 1 && item.charAt(i - 1) == userInput.charAt(j - 2) + && item.charAt(i - 2) == userInput.charAt(j - 1)) { + currentRow[j] = Math.min(currentRow[j], previousRow[j - 2] + substitutionCost); + } } // Swap rows @@ -119,7 +125,7 @@ private static int computeLevenshteinDistance(String s1, String s2) { currentRow = tempRow; } - // Return the Levenshtein distance + // Return the Damerau-Levenshtein distance assert previousRow[n] >= 0 : "Levenshtein distance cannot be negative"; return previousRow[n]; } diff --git a/src/main/java/florizz/core/Parser.java b/src/main/java/florizz/core/Parser.java index 5b0645e72b..d3a6760e8e 100644 --- a/src/main/java/florizz/core/Parser.java +++ b/src/main/java/florizz/core/Parser.java @@ -84,26 +84,47 @@ public static Command parse (String input) throws FlorizzException { /** - * Splits input into command and arguments. Also handles capitalisation and space exceptions + * Splits input into command and arguments (if any). Handles capitalisation, whitespaces and small typos. * * @param input - * @return String[] output; output[0] = command ; output[1] arguments + * @return String[] output; output[0] = item ; output[1] = argument(s) */ + private static String[] commandHandler(String input) throws FlorizzException { - String[] output = new String[2]; - String trimmedInput = input.trim(); - int firstWhitespace = trimmedInput.indexOf(" "); - if (firstWhitespace != -1) { - // input have arguments - output[0] = FuzzyLogic.detectItem(trimmedInput.substring(0,firstWhitespace).toLowerCase()); - output[1] = FuzzyLogic.detectItem(trimmedInput.substring(firstWhitespace).trim()); - } else { - output[0] = FuzzyLogic.detectItem(trimmedInput.toLowerCase()); + String[] outputs = new String[2]; + try { + String trimmedInput = input.trim(); + int firstWhitespace = trimmedInput.indexOf(" "); + if (firstWhitespace != -1) { + outputs[0] = FuzzyLogic.detectItem(trimmedInput.substring(0,firstWhitespace).toLowerCase()); + switch (outputs[0]) { + case ("delete"): // Fallthrough + case ("new"): + outputs[1] = trimmedInput.substring(firstWhitespace).trim(); + break; + case ("remove"): // Fallthrough + case ("add"): + String[] arguments = new String[2]; + String trimmedArgument = trimmedInput.substring(firstWhitespace).trim(); + int secondWhitespace = trimmedArgument.indexOf(" "); + arguments[0] = FuzzyLogic.detectItem(trimmedArgument.substring(0,secondWhitespace).toLowerCase()); + arguments[1] = trimmedArgument.substring(secondWhitespace).trim(); + outputs[1] = arguments[0] + " " + arguments[1]; + break; + default: + outputs[1] = FuzzyLogic.detectItem(trimmedInput.substring(firstWhitespace).trim()); + break; + } + } else { + outputs[0] = FuzzyLogic.detectItem(trimmedInput.toLowerCase()); + } + } catch (FlorizzException ex) { + Logger.getLogger("CommandHandler").log(Level.SEVERE, "Exception occurred in commandHandler", ex); + throw ex; } - return output; + return outputs; } - /** * remove prefix from an input string * e.g. "/to For Mom" -> " For Mom" From ca1c508f56a8ac3ffc177e027293be1e2edbee70 Mon Sep 17 00:00:00 2001 From: Jeffinson Darmawan Date: Tue, 2 Apr 2024 01:29:09 +0800 Subject: [PATCH 2/2] Fixed minor bug --- src/main/java/florizz/core/Parser.java | 2 +- src/main/java/florizz/core/Ui.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/florizz/core/Parser.java b/src/main/java/florizz/core/Parser.java index d3a6760e8e..9c6d253115 100644 --- a/src/main/java/florizz/core/Parser.java +++ b/src/main/java/florizz/core/Parser.java @@ -107,7 +107,7 @@ private static String[] commandHandler(String input) throws FlorizzException { String[] arguments = new String[2]; String trimmedArgument = trimmedInput.substring(firstWhitespace).trim(); int secondWhitespace = trimmedArgument.indexOf(" "); - arguments[0] = FuzzyLogic.detectItem(trimmedArgument.substring(0,secondWhitespace).toLowerCase()); + arguments[0] = FuzzyLogic.detectItem(trimmedArgument.substring(0,secondWhitespace)); arguments[1] = trimmedArgument.substring(secondWhitespace).trim(); outputs[1] = arguments[0] + " " + arguments[1]; break; diff --git a/src/main/java/florizz/core/Ui.java b/src/main/java/florizz/core/Ui.java index 272205ee09..7756e4ceff 100644 --- a/src/main/java/florizz/core/Ui.java +++ b/src/main/java/florizz/core/Ui.java @@ -66,7 +66,7 @@ public void printBouquetDeleted(Bouquet bouquetDeleted){ * @param bouquetList The list of saved bouquets. */ public void printAllBouquets(ArrayList bouquetList){ - System.out.println("Here are the list of your saved bouquets:"); + System.out.println("Here is the list of your saved bouquets:"); int i = 1; double totalPrice = 0; for (Bouquet bouquet : bouquetList){