Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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>.
Expand All @@ -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(
Expand All @@ -44,8 +46,8 @@ private static <E> int calculateCost(final SimilarityInput<E> left, final Simila
// 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,14 @@ static Stream<Arguments> limitedDamerauLevenshteinDistanceTestCases() {
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)
);
}

Expand Down Expand Up @@ -123,7 +130,16 @@ static Stream<Arguments> unlimitedDamerauLevenshteinDistanceTestCases() {
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)
);
}

Expand Down
Loading