jamoLevenshteinDistance static method

double jamoLevenshteinDistance(
  1. String s1,
  2. String s2, {
  3. PhonemeCost? phonemeCost,
  4. bool debug = false,
})

Computes the Levenshtein distance between two Korean strings based on decomposed phonemes.

Parameters:

  • s1 : The first Korean string.
  • s2 : The second Korean string.
  • phonemeCost : Customized weights for different phonemes.
  • debug : Whether to print debugging information.

Returns the Levenshtein distance between the two strings.

Implementation

static double jamoLevenshteinDistance(String s1, String s2,
    {PhonemeCost? phonemeCost, bool debug = false}) {
  if (s1.length < s2.length) {
    return jamoLevenshteinDistance(s2, s1, debug: debug);
  }

  if (s2.isEmpty) return s1.length.toDouble();

  double substitutionCost(String c1, String c2) {
    if (c1 == c2) return 0;

    final decomposedC1 = c1.decompose();
    final decomposedC2 = c2.decompose();

    if (decomposedC1 == null || decomposedC2 == null) {
      throw const NonKoreanContainsException();
    }
    return _levenshtein(
          decomposedC1.join(),
          decomposedC2.join(),
          phonemeCost: phonemeCost,
        ) /
        3;
  }

  List<double> previousRow =
      List<double>.generate(s2.length + 1, (int index) => index.toDouble());

  for (int i = 0; i < s1.length; i++) {
    List<double> currentRow = [i + _defaultDistanceCost];

    for (int j = 0; j < s2.length; j++) {
      double insertions = previousRow[j + 1] + _defaultDistanceCost;
      double deletions = currentRow[j] + _defaultDistanceCost;
      double substitutions = previousRow[j] + substitutionCost(s1[i], s2[j]);
      currentRow.add([insertions, deletions, substitutions]
          .reduce((a, b) => a < b ? a : b));
    }

    if (debug) {
      print(currentRow
          .sublist(1)
          .map((double v) => v.toStringAsFixed(3))
          .toList());
    }

    previousRow = currentRow;
  }

  return previousRow.last;
}