partialRatio function

double partialRatio(
  1. String s1,
  2. String s2, {
  3. double scoreCutoff = 0.0,
})

Calculates a partial ratio between two strings Matches the behavior of RapidFuzz's partial_ratio implementation

Implementation

double partialRatio(String s1, String s2, {double scoreCutoff = 0.0}) {
  final len1 = s1.length;
  final len2 = s2.length;

  // RapidFuzz swaps the strings to ensure s1 is always the shorter one
  if (len1 > len2) {
    return partialRatio(s2, s1, scoreCutoff: scoreCutoff);
  }

  // Handle cutoff > 100
  if (scoreCutoff > 100) return 0.0;

  // Handle empty strings - RapidFuzz returns 100 if both empty, 0 otherwise
  if (len1 == 0 || len2 == 0) {
    return (len1 == len2) ? 100.0 : 0.0;
  }

  // Perfect match
  if (s1 == s2) return 100.0;

  // Find best substring match
  var bestScore = 0.0;

  // When len2 > len1, try to find the best matching substring
  if (len2 > len1) {
    // Try all possible substrings of s2 with length len1
    for (var i = 0; i <= len2 - len1; i++) {
      final subStr = s2.substring(i, i + len1);
      final currentScore = ratio(s1, subStr, scoreCutoff: bestScore);
      bestScore = max(bestScore, currentScore);
      if (bestScore == 100.0) return 100.0;
    }
  }

  // For strings of same length, check ratio in both directions
  if (s1.length == s2.length && bestScore != 100.0) {
    final reversedScore = ratio(s2, s1, scoreCutoff: bestScore);
    bestScore = max(bestScore, reversedScore);
  }

  // Also check beginning and end of string s2 for partial matches
  // Check partial matches with the beginning of s2 (increasing size)
  for (var i = 1; i < len1; i++) {
    final s1Substr = s1.substring(0, i);
    final s2Substr = s2.substring(0, i);
    if (s1.codeUnitAt(i - 1) != s2.codeUnitAt(i - 1)) continue;

    final currentScore = ratio(s1Substr, s2Substr, scoreCutoff: bestScore);
    if (currentScore > bestScore) {
      bestScore = currentScore;
      if (bestScore == 100.0) return 100.0;
    }
  }

  // Check partial matches with the end of s2 (decreasing size)
  for (var i = len2 - 1; i >= len2 - len1; i--) {
    final s1Substr = s1.substring(len1 - (len2 - i));
    final s2Substr = s2.substring(i);
    if (s1.codeUnitAt(0) != s2.codeUnitAt(i)) continue;

    final currentScore = ratio(s1Substr, s2Substr, scoreCutoff: bestScore);
    if (currentScore > bestScore) {
      bestScore = currentScore;
      if (bestScore == 100.0) return 100.0;
    }
  }

  return bestScore;
}