This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git


The following commit(s) were added to refs/heads/master by this push:
     new 14657580 Compare characters by value in DamerauLevenshteinDistance 
(#770)
14657580 is described below

commit 14657580972a27e504d08c1057699aaa31e0e6bc
Author: Weiki <[email protected]>
AuthorDate: Thu Sep 3 19:22:57 2026 +0800

    Compare characters by value in DamerauLevenshteinDistance (#770)
    
    calculateCost compared the boxed Character values returned by
    SimilarityInput.at with ==, so it only recognized equal characters
    that Character.valueOf caches. That cache covers values up to 127,
    so every non-ASCII character compared unequal to itself: applying the
    distance to "caf\u00e9" and "caf\u00e9" reported 1 instead of 0, and a
    two-character CJK input compared against itself reported 2. The
    adjacent-transposition branch never fired for non-ASCII input either,
    so transposing two accented characters cost 2 instead of 1. The
    limited variant was affected the same way and could return -1 for
    inputs whose real distance is within the threshold.
    
    Compare with Objects.equals instead, matching every other class in
    this package: LevenshteinDistance, LevenshteinDetailedDistance,
    JaroWinklerSimilarity and HammingDistance all use equals on the
    values from at.
---
 .../text/similarity/DamerauLevenshteinDistance.java  |  8 +++++---
 .../similarity/DamerauLevenshteinDistanceTest.java   | 20 ++++++++++++++++++--
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/text/similarity/DamerauLevenshteinDistance.java
 
b/src/main/java/org/apache/commons/text/similarity/DamerauLevenshteinDistance.java
index b266c1ca..68a55f5c 100644
--- 
a/src/main/java/org/apache/commons/text/similarity/DamerauLevenshteinDistance.java
+++ 
b/src/main/java/org/apache/commons/text/similarity/DamerauLevenshteinDistance.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.text.similarity;
 
+import java.util.Objects;
+
 /**
  * An algorithm for measuring the difference between two character sequences 
using the
  * <a 
href="https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance";>Damerau-Levenshtein
 Distance</a>.
@@ -32,7 +34,7 @@ public class DamerauLevenshteinDistance implements 
EditDistance<Integer> {
 
     private static <E> int calculateCost(final SimilarityInput<E> left, final 
SimilarityInput<E> right, final int leftIndex, final int rightIndex,
             final int[] curr, final int[] prev, final int[] prevPrev) {
-        final int cost = left.at(leftIndex - 1) == right.at(rightIndex - 1) ? 
0 : 1;
+        final int cost = Objects.equals(left.at(leftIndex - 1), 
right.at(rightIndex - 1)) ? 0 : 1;
         // Select cheapest operation
         int value = Math.min(
                 Math.min(
@@ -44,8 +46,8 @@ public class DamerauLevenshteinDistance implements 
EditDistance<Integer> {
         // Check if adjacent characters are the same -> transpose if cheaper
         if (leftIndex > 1
                 && rightIndex > 1
-                && left.at(leftIndex - 1) == right.at(rightIndex - 2)
-                && left.at(leftIndex - 2) == right.at(rightIndex - 1)) {
+                && Objects.equals(left.at(leftIndex - 1), right.at(rightIndex 
- 2))
+                && Objects.equals(left.at(leftIndex - 2), right.at(rightIndex 
- 1))) {
             // Use cost here, to properly handle two subsequent equal letters
             value = Math.min(value, prevPrev[rightIndex - 2] + cost);
         }
diff --git 
a/src/test/java/org/apache/commons/text/similarity/DamerauLevenshteinDistanceTest.java
 
b/src/test/java/org/apache/commons/text/similarity/DamerauLevenshteinDistanceTest.java
index 65f664bb..a532ba31 100644
--- 
a/src/test/java/org/apache/commons/text/similarity/DamerauLevenshteinDistanceTest.java
+++ 
b/src/test/java/org/apache/commons/text/similarity/DamerauLevenshteinDistanceTest.java
@@ -77,7 +77,14 @@ public class DamerauLevenshteinDistanceTest {
                 Arguments.of("xyxyxyxyxy", "yxyxyxyxyx", 4, 2),
                 Arguments.of("aaaaabbbbbccccc", "cccccbbbbbaaaaa", 5, -1),
                 Arguments.of("thequickbrownfoxjumpsoverthelazydog", 
"thequickbrownfoxjumpsovrethelazydog", 1, 1),
-                Arguments.of("antidisestablishmentarianism", 
"antidisestablishmentarianisn", 3, 1)
+                Arguments.of("antidisestablishmentarianism", 
"antidisestablishmentarianisn", 3, 1),
+                // Non-ASCII characters are outside the Character.valueOf 
cache, so identical inputs must still measure zero.
+                Arguments.of("caf\u00e9", "caf\u00e9", 1, 0),
+                Arguments.of("\u4f60\u597d", "\u4f60\u597d", 1, 0),
+                Arguments.of("na\u00efve", "na\u00efve", 1, 0),
+                // Transposing two adjacent non-ASCII characters costs one 
edit, exactly as it does for ASCII.
+                Arguments.of("caf\u00e9\u00e8", "caf\u00e8\u00e9", 1, 1),
+                Arguments.of("\u4f60\u597d", "\u597d\u4f60", 1, 1)
         );
     }
 
@@ -123,7 +130,16 @@ public class DamerauLevenshteinDistanceTest {
                 Arguments.of("xyxyxyxyxy", "yxyxyxyxyx", 2),
                 Arguments.of("aaaaabbbbbccccc", "cccccbbbbbaaaaa", 10),
                 Arguments.of("thequickbrownfoxjumpsoverthelazydog", 
"thequickbrownfoxjumpsovrethelazydog", 1),
-                Arguments.of("antidisestablishmentarianism", 
"antidisestablishmentarianisn", 1)
+                Arguments.of("antidisestablishmentarianism", 
"antidisestablishmentarianisn", 1),
+                // Non-ASCII characters are outside the Character.valueOf 
cache, so identical inputs must still measure zero.
+                Arguments.of("caf\u00e9", "caf\u00e9", 0),
+                Arguments.of("\u4f60\u597d", "\u4f60\u597d", 0),
+                Arguments.of("na\u00efve", "na\u00efve", 0),
+                Arguments.of("\ud83d\ude00", "\ud83d\ude00", 0),
+                // Transposing two adjacent non-ASCII characters costs one 
edit, exactly as it does for ASCII.
+                Arguments.of("caf\u00e9\u00e8", "caf\u00e8\u00e9", 1),
+                Arguments.of("\u4f60\u597d", "\u597d\u4f60", 1),
+                Arguments.of("\u00e9x", "x\u00e9", 1)
         );
     }
 

Reply via email to