normalize($left); $right = $this->normalize($right); $leftLength = strlen($left); $rightLength = strlen($right); $matrix = []; // Transforming a prefix into an empty string requires deleting every digit. for ($row = 0; $row <= $leftLength; $row++) { $matrix[$row] = [$row]; } // Transforming an empty string into a prefix requires inserting every digit. for ($column = 0; $column <= $rightLength; $column++) { $matrix[0][$column] = $column; } for ($row = 1; $row <= $leftLength; $row++) { for ($column = 1; $column <= $rightLength; $column++) { $substitutionCost = $left[$row - 1] === $right[$column - 1] ? 0 : 1; $deletionDistance = $matrix[$row - 1][$column] + 1; $insertionDistance = $matrix[$row][$column - 1] + 1; $substitutionDistance = $matrix[$row - 1][$column - 1] + $substitutionCost; // Keep the cheapest way to align the two prefixes at this position. $matrix[$row][$column] = min( $deletionDistance, $insertionDistance, $substitutionDistance, ); // Count two adjacent inverted digits as one edit instead of two substitutions. if ( $row > 1 && $column > 1 && $left[$row - 1] === $right[$column - 2] && $left[$row - 2] === $right[$column - 1] ) { $matrix[$row][$column] = min( $matrix[$row][$column], $matrix[$row - 2][$column - 2] + 1, ); } } } return $matrix[$leftLength][$rightLength]; } /** * Keep only digits and left-pad seven-digit DNIs so comparisons preserve * the leading zero that is present when the DNI is extracted from a CUIT. */ public function normalize(string $dni): string { $digits = preg_replace('/\D+/', '', $dni) ?? ''; return str_pad($digits, 8, '0', STR_PAD_LEFT); } }