static int best_distance(const char*const*const suggs, const char *const word, size_t len) { int best_dist; const char*const* sugg_it; char* normalized_word; normalized_word = g_utf8_normalize (word, len, G_NORMALIZE_NFD); best_dist = g_utf8_strlen(normalized_word, -1); if(suggs) { for(sugg_it = suggs; *sugg_it; ++sugg_it) { char* normalized_sugg; int dist; normalized_sugg = g_utf8_normalize (*sugg_it, -1, G_NORMALIZE_NFD); dist = edit_dist(normalized_word, normalized_sugg); g_free(normalized_sugg); if (dist < best_dist) best_dist = dist; } } g_free(normalized_word); return best_dist; }
// Exercises edit_dist on a and b. If the result matches the expected value, // returns 0. If not, displays the message and returns 1. int run_test(char *a, char *b, int expected, char *msg) { int actual = edit_dist(a,b); if (actual == expected) return 0; printf ("FAIL: Expected %d, got %d for %s:%s, %s\n", expected, actual, a, b, msg); return 1; }
static void enchant_trie_find_matches(EnchantTrie* trie,EnchantTrieMatcher *matcher) { int errs = 0; ssize_t nxtChI = 0, oldPos = 0; char* nxtChS = NULL; EnchantTrie* subtrie = NULL; g_return_if_fail(matcher); /* Can't match in the empty trie */ if(trie == NULL) { return; } /* Bail out if over the error limits */ if(matcher->num_errors > matcher->max_errors){ return; } /* If the end of a string has been reached, no point recursing */ if (trie == EOSTrie) { size_t word_len = strlen(matcher->word); errs = matcher->num_errors; if((ssize_t)word_len > matcher->word_pos) { matcher->num_errors = errs + word_len - matcher->word_pos; } if (matcher->num_errors <= matcher->max_errors) { matcher->cbfunc(g_strdup(matcher->path),matcher); } matcher->num_errors = errs; return; } /* If there is a value, just check it, no recursion */ if (trie->value != NULL) { gchar* value; errs = matcher->num_errors; value = trie->value; if(matcher->mode == case_insensitive) { value = g_utf8_strdown(value, -1); } matcher->num_errors = errs + edit_dist(value, &(matcher->word[matcher->word_pos])); if(matcher->mode == case_insensitive) { g_free(value); } if (matcher->num_errors <= matcher->max_errors) { matcher->cbfunc(g_strconcat(matcher->path, trie->value,NULL), matcher); } matcher->num_errors = errs; return; } nxtChI = (ssize_t)(g_utf8_next_char(&matcher->word[matcher->word_pos]) - matcher->word); nxtChS = g_strndup(&matcher->word[matcher->word_pos], (nxtChI - matcher->word_pos)); /* Precisely match the first character, and recurse */ subtrie = enchant_trie_get_subtrie(trie, matcher, &nxtChS); if (subtrie != NULL) { enchant_trie_matcher_pushpath(matcher,nxtChS); oldPos = matcher->word_pos; matcher->word_pos = nxtChI; enchant_trie_find_matches(subtrie,matcher); matcher->word_pos = oldPos; enchant_trie_matcher_poppath(matcher,strlen(nxtChS)); } g_free(nxtChS); matcher->num_errors++; if (matcher->word[matcher->word_pos] != '\0') { /* Match on inserting word[0] */ oldPos = matcher->word_pos; matcher->word_pos = nxtChI; enchant_trie_find_matches(trie,matcher); matcher->word_pos = oldPos; } /* for each subtrie, match on delete or substitute word[0] or transpose word[0] and word[1] */ g_hash_table_foreach(trie->subtries, enchant_trie_find_matches_cb, matcher); matcher->num_errors--; }