[api] Fixing multi-language expansions with overlapping expansions, whitespace, utf8 normalization of canonical strings

This commit is contained in:
Al
2016-02-08 02:50:34 -05:00
parent 0695738253
commit 84d5ba18f0

View File

@@ -43,6 +43,18 @@ static inline uint64_t get_normalize_token_options(normalize_options_t options)
return normalize_token_options; return normalize_token_options;
} }
static inline uint64_t get_normalize_string_options(normalize_options_t options) {
uint64_t normalize_string_options = 0;
normalize_string_options |= options.transliterate ? NORMALIZE_STRING_TRANSLITERATE : 0;
normalize_string_options |= options.latin_ascii ? NORMALIZE_STRING_LATIN_ASCII : 0;
normalize_string_options |= options.decompose ? NORMALIZE_STRING_DECOMPOSE : 0;
normalize_string_options |= options.strip_accents ? NORMALIZE_STRING_STRIP_ACCENTS : 0;
normalize_string_options |= options.lowercase ? NORMALIZE_STRING_LOWERCASE : 0;
normalize_string_options |= options.trim_string ? NORMALIZE_STRING_TRIM : 0;
return normalize_string_options;
}
static void add_normalized_strings_token(cstring_array *strings, char *str, token_t token, normalize_options_t options) { static void add_normalized_strings_token(cstring_array *strings, char *str, token_t token, normalize_options_t options) {
uint64_t normalize_token_options = get_normalize_token_options(options); uint64_t normalize_token_options = get_normalize_token_options(options);
@@ -132,6 +144,7 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
for (int j = 0; j < lang_phrases->n; j++) { for (int j = 0; j < lang_phrases->n; j++) {
phrase_t p = lang_phrases->a[j]; phrase_t p = lang_phrases->a[j];
log_debug("lang=%s, (%d, %d)\n", lang, p.start, p.len);
phrase_language_array_push(phrases, (phrase_language_t){lang, p}); phrase_language_array_push(phrases, (phrase_language_t){lang, p});
} }
@@ -155,6 +168,7 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
bool last_added_was_whitespace = false; bool last_added_was_whitespace = false;
uint64_t normalize_string_options = get_normalize_string_options(options);
if (phrases != NULL) { if (phrases != NULL) {
log_debug("phrases not NULL, n=%zu\n", phrases->n); log_debug("phrases not NULL, n=%zu\n", phrases->n);
@@ -166,6 +180,7 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
int end = 0; int end = 0;
phrase_t phrase = NULL_PHRASE; phrase_t phrase = NULL_PHRASE;
phrase_t prev_phrase = NULL_PHRASE;
key = key != NULL ? key : char_array_new_size(DEFAULT_KEY_LEN); key = key != NULL ? key : char_array_new_size(DEFAULT_KEY_LEN);
@@ -173,7 +188,11 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
phrase_lang = phrases->a[i]; phrase_lang = phrases->a[i];
phrase = phrase_lang.phrase; phrase = phrase_lang.phrase;
if (phrase.start < start) {
log_debug("phrase.start=%d, phrase.len=%d, lang=%s, prev_phrase.start=%d, prev_phrase.len=%d\n", phrase.start, phrase.len, phrase_lang.language, prev_phrase.start, prev_phrase.len);
if ((phrase.start > prev_phrase.start && phrase.start < prev_phrase.start + prev_phrase.len) || (phrase.start == prev_phrase.start && i > 0 && phrase.len < prev_phrase.len)) {
log_debug("continuing\n");
continue; continue;
} }
@@ -186,7 +205,9 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
end = phrase.start; end = phrase.start;
log_debug("start=%d, end=%d\n", start, end);
for (int j = start; j < end; j++) { for (int j = start; j < end; j++) {
log_debug("Adding token %d\n", j);
token_t token = tokens->a[j]; token_t token = tokens->a[j];
if (is_punctuation(token.type)) { if (is_punctuation(token.type)) {
last_was_punctuation = true; last_was_punctuation = true;
@@ -201,19 +222,24 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
log_debug("Adding previous token, %.*s\n", (int)token.len, str + token.offset); log_debug("Adding previous token, %.*s\n", (int)token.len, str + token.offset);
string_tree_add_string_len(tree, str + token.offset, token.len); string_tree_add_string_len(tree, str + token.offset, token.len);
} else { last_added_was_whitespace = false;
log_debug("Adding space\n"); } else if (!last_added_was_whitespace) {
log_debug("Adding pre-phrase whitespace\n");
last_added_was_whitespace = true; last_added_was_whitespace = true;
string_tree_add_string(tree, " "); string_tree_add_string(tree, " ");
} else {
continue;
} }
last_was_punctuation = false; last_was_punctuation = false;
string_tree_finalize_token(tree); string_tree_finalize_token(tree);
} }
if (phrase.start > 0) { if (phrase.start > 0 && start < end) {
token_t prev_token = tokens->a[phrase.start - 1]; token_t prev_token = tokens->a[phrase.start - 1];
log_debug("last_added_was_whitespace=%d\n", last_added_was_whitespace);
if (!last_added_was_whitespace && phrase.start - 1 > 0 && (!is_ideographic(prev_token.type) || last_was_punctuation)) { if (!last_added_was_whitespace && phrase.start - 1 > 0 && (!is_ideographic(prev_token.type) || last_was_punctuation)) {
log_debug("Adding space III\n");
string_tree_add_string(tree, " "); string_tree_add_string(tree, " ");
last_added_was_whitespace = true; last_added_was_whitespace = true;
string_tree_finalize_token(tree); string_tree_finalize_token(tree);
@@ -247,12 +273,19 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
address_expansion_t expansion = expansions->a[j]; address_expansion_t expansion = expansions->a[j];
if (expansion.canonical_index != NULL_CANONICAL_INDEX) { if (expansion.canonical_index != NULL_CANONICAL_INDEX) {
char *canonical = address_dictionary_get_canonical(expansion.canonical_index); char *canonical = address_dictionary_get_canonical(expansion.canonical_index);
char *canonical_normalized = normalize_string_utf8(canonical, normalize_string_options);
canonical = canonical_normalized != NULL ? canonical_normalized : canonical;
if (phrase.start + phrase.len < tokens->n - 1) { if (phrase.start + phrase.len < tokens->n - 1) {
token_t next_token = tokens->a[phrase.start + phrase.len]; token_t next_token = tokens->a[phrase.start + phrase.len];
if (!is_numeric_token(next_token.type)) { if (!is_numeric_token(next_token.type)) {
log_debug("non-canonical phrase, adding canonical string\n");
string_tree_add_string(tree, canonical); string_tree_add_string(tree, canonical);
last_added_was_whitespace = false; last_added_was_whitespace = false;
} else { } else {
log_debug("adding canonical with cstring_array methods\n");
uint32_t start_index = cstring_array_start_token(tree->strings); uint32_t start_index = cstring_array_start_token(tree->strings);
cstring_array_append_string(tree->strings, canonical); cstring_array_append_string(tree->strings, canonical);
cstring_array_append_string(tree->strings, " "); cstring_array_append_string(tree->strings, " ");
@@ -264,7 +297,13 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
last_added_was_whitespace = false; last_added_was_whitespace = false;
} }
if (canonical_normalized != NULL) {
free(canonical_normalized);
}
} else { } else {
log_debug("canonical phrase, adding canonical string\n");
uint32_t start_index = cstring_array_start_token(tree->strings); uint32_t start_index = cstring_array_start_token(tree->strings);
for (int k = phrase.start; k < phrase.start + phrase.len; k++) { for (int k = phrase.start; k < phrase.start + phrase.len; k++) {
token = tokens->a[k]; token = tokens->a[k];
@@ -272,45 +311,62 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
cstring_array_append_string_len(tree->strings, str + token.offset, token.len); cstring_array_append_string_len(tree->strings, str + token.offset, token.len);
last_added_was_whitespace = false; last_added_was_whitespace = false;
} else { } else {
log_debug("space\n");
cstring_array_append_string(tree->strings, " "); cstring_array_append_string(tree->strings, " ");
last_added_was_whitespace = true; last_added_was_whitespace = true;
} }
} }
cstring_array_terminate(tree->strings); cstring_array_terminate(tree->strings);
} }
} }
string_tree_finalize_token(tree);
} }
} else { } else {
uint32_t start_index = cstring_array_start_token(tree->strings);
for (int j = phrase.start; j < phrase.start + phrase.len; j++) { for (int j = phrase.start; j < phrase.start + phrase.len; j++) {
token = tokens->a[j]; token = tokens->a[j];
if (token.type != WHITESPACE) { if (token.type != WHITESPACE) {
log_debug("Adding previous token, %.*s\n", (int)token.len, str + token.offset); log_debug("Adding canonical token, %.*s\n", (int)token.len, str + token.offset);
string_tree_add_string_len(tree, str + token.offset, token.len); cstring_array_append_string_len(tree->strings, str + token.offset, token.len);
last_added_was_whitespace = false; last_added_was_whitespace = false;
} else if (!last_added_was_whitespace) { } else if (!last_added_was_whitespace) {
string_tree_add_string(tree, " "); log_debug("Adding space\n");
cstring_array_append_string(tree->strings, " ");
last_added_was_whitespace = true; last_added_was_whitespace = true;
} }
string_tree_finalize_token(tree);
} }
if (phrase.start + phrase.len < tokens->n - 1) { if (phrase.start + phrase.len < tokens->n - 1) {
token_t next_token = tokens->a[phrase.start + phrase.len + 1]; token_t next_token = tokens->a[phrase.start + phrase.len + 1];
if (next_token.type != WHITESPACE && !last_added_was_whitespace && !is_ideographic(next_token.type)) { if (next_token.type != WHITESPACE && !last_added_was_whitespace && !is_ideographic(next_token.type)) {
string_tree_add_string(tree, " "); cstring_array_append_string(tree->strings, " ");
last_added_was_whitespace = true; last_added_was_whitespace = true;
string_tree_finalize_token(tree);
} }
} }
cstring_array_terminate(tree->strings);
}
log_debug("i=%d\n", i);
bool end_of_phrase = false;
if (i < phrases->n - 1) {
phrase_t next_phrase = phrases->a[i + 1].phrase;
end_of_phrase = (next_phrase.start != phrase.start || next_phrase.len != phrase.len);
} else {
end_of_phrase = true;
}
log_debug("end_of_phrase=%d\n", end_of_phrase);
if (end_of_phrase) {
log_debug("finalize at i=%d\n", i);
string_tree_finalize_token(tree);
} }
start = phrase.start + phrase.len; start = phrase.start + phrase.len;
prev_phrase = phrase;
} }
@@ -321,6 +377,7 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
if (phrase.start + phrase.len > 0 && phrase.start + phrase.len <= end - 1) { if (phrase.start + phrase.len > 0 && phrase.start + phrase.len <= end - 1) {
token_t next_token = tokens->a[phrase.start + phrase.len]; token_t next_token = tokens->a[phrase.start + phrase.len];
if (next_token.type != WHITESPACE && !last_added_was_whitespace && !is_ideographic(next_token.type)) { if (next_token.type != WHITESPACE && !last_added_was_whitespace && !is_ideographic(next_token.type)) {
log_debug("space after phrase\n");
string_tree_add_string(tree, " "); string_tree_add_string(tree, " ");
last_added_was_whitespace = true; last_added_was_whitespace = true;
string_tree_finalize_token(tree); string_tree_finalize_token(tree);
@@ -329,14 +386,17 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
for (int j = start; j < end; j++) { for (int j = start; j < end; j++) {
log_debug("On token %d\n", j);
token_t token = tokens->a[j]; token_t token = tokens->a[j];
if (is_punctuation(token.type)) { if (is_punctuation(token.type)) {
log_debug("last_was_punctuation\n");
last_was_punctuation = true; last_was_punctuation = true;
continue; continue;
} }
if (token.type != WHITESPACE) { if (token.type != WHITESPACE) {
if (j > 0 && last_was_punctuation && !last_added_was_whitespace) { if (j > 0 && last_was_punctuation && !last_added_was_whitespace) {
log_debug("Adding another space\n");
string_tree_add_string(tree, " "); string_tree_add_string(tree, " ");
string_tree_finalize_token(tree); string_tree_finalize_token(tree);
} }
@@ -344,10 +404,13 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
string_tree_add_string_len(tree, str + token.offset, token.len); string_tree_add_string_len(tree, str + token.offset, token.len);
last_added_was_whitespace = false; last_added_was_whitespace = false;
} else { } else if (!last_added_was_whitespace) {
log_debug("Adding space\n"); log_debug("Adding space IV\n");
string_tree_add_string(tree, " "); string_tree_add_string(tree, " ");
last_added_was_whitespace = true; last_added_was_whitespace = true;
} else {
log_debug("Skipping token %d\n", j);
continue;
} }
last_was_punctuation = false; last_was_punctuation = false;
@@ -359,23 +422,29 @@ static string_tree_t *add_string_alternatives(char *str, normalize_options_t opt
} else { } else {
for (int j = 0; j < tokens->n; j++) { for (int j = 0; j < tokens->n; j++) {
log_debug("On token %d\n", j);
token_t token = tokens->a[j]; token_t token = tokens->a[j];
if (is_punctuation(token.type)) { if (is_punctuation(token.type)) {
log_debug("punctuation, skipping\n");
last_was_punctuation = true; last_was_punctuation = true;
continue; continue;
} }
if (token.type != WHITESPACE) { if (token.type != WHITESPACE) {
if (last_was_punctuation && !last_added_was_whitespace) { if (last_was_punctuation && !last_added_was_whitespace) {
log_debug("Adding space V\n");
string_tree_add_string(tree, " "); string_tree_add_string(tree, " ");
string_tree_finalize_token(tree); string_tree_finalize_token(tree);
} }
string_tree_add_string_len(tree, str + token.offset, token.len); string_tree_add_string_len(tree, str + token.offset, token.len);
last_added_was_whitespace = false; last_added_was_whitespace = false;
} else { } else if (!last_added_was_whitespace) {
log_debug("Adding space VI\n");
string_tree_add_string(tree, " "); string_tree_add_string(tree, " ");
last_added_was_whitespace = true; last_added_was_whitespace = true;
} else {
continue;
} }
last_was_punctuation = false; last_was_punctuation = false;
@@ -431,10 +500,17 @@ static address_expansion_array *get_affix_expansions(char_array *key, char *str,
return expansions; return expansions;
} }
static inline void cat_affix_expansion(char_array *key, char *str, address_expansion_t expansion, token_t token, phrase_t phrase) { static inline void cat_affix_expansion(char_array *key, char *str, address_expansion_t expansion, token_t token, phrase_t phrase, normalize_options_t options) {
if (expansion.canonical_index != NULL_CANONICAL_INDEX) { if (expansion.canonical_index != NULL_CANONICAL_INDEX) {
char *canonical = address_dictionary_get_canonical(expansion.canonical_index); char *canonical = address_dictionary_get_canonical(expansion.canonical_index);
uint64_t normalize_string_options = get_normalize_string_options(options);
char *canonical_normalized = normalize_string_utf8(canonical, normalize_string_options);
canonical = canonical_normalized != NULL ? canonical_normalized : canonical;
char_array_cat(key, canonical); char_array_cat(key, canonical);
if (canonical_normalized != NULL) {
free(canonical_normalized);
}
} else { } else {
char_array_cat_len(key, str + token.offset + phrase.start, phrase.len); char_array_cat_len(key, str + token.offset + phrase.start, phrase.len);
} }
@@ -489,7 +565,7 @@ static bool add_affix_expansions(string_tree_t *tree, char *str, char *lang, tok
prefix_expansion = prefix_expansions->a[i]; prefix_expansion = prefix_expansions->a[i];
char_array_clear(key); char_array_clear(key);
cat_affix_expansion(key, str, prefix_expansion, token, prefix); cat_affix_expansion(key, str, prefix_expansion, token, prefix, options);
prefix_start = key->n - 1; prefix_start = key->n - 1;
add_space = (int)prefix_expansion.separable; add_space = (int)prefix_expansion.separable;
@@ -531,7 +607,7 @@ static bool add_affix_expansions(string_tree_t *tree, char *str, char *lang, tok
char_array_cat(key, " "); char_array_cat(key, " ");
} }
cat_affix_expansion(key, str, suffix_expansion, token, suffix); cat_affix_expansion(key, str, suffix_expansion, token, suffix, options);
expansion = char_array_get_string(key); expansion = char_array_get_string(key);
cstring_array_add_string(strings, expansion); cstring_array_add_string(strings, expansion);
@@ -550,7 +626,7 @@ static bool add_affix_expansions(string_tree_t *tree, char *str, char *lang, tok
key->n = prefix_end; key->n = prefix_end;
suffix_expansion = suffix_expansions->a[j]; suffix_expansion = suffix_expansions->a[j];
cat_affix_expansion(key, str, suffix_expansion, token, suffix); cat_affix_expansion(key, str, suffix_expansion, token, suffix, options);
expansion = char_array_get_string(key); expansion = char_array_get_string(key);
cstring_array_add_string(tree->strings, expansion); cstring_array_add_string(tree->strings, expansion);
@@ -585,7 +661,7 @@ static bool add_affix_expansions(string_tree_t *tree, char *str, char *lang, tok
char_array_cat(key, " "); char_array_cat(key, " ");
} }
cat_affix_expansion(key, str, suffix_expansion, token, suffix); cat_affix_expansion(key, str, suffix_expansion, token, suffix, options);
expansion = char_array_get_string(key); expansion = char_array_get_string(key);
cstring_array_add_string(tree->strings, expansion); cstring_array_add_string(tree->strings, expansion);
@@ -620,7 +696,7 @@ static bool add_affix_expansions(string_tree_t *tree, char *str, char *lang, tok
char_array_clear(key); char_array_clear(key);
prefix_expansion = prefix_expansions->a[j]; prefix_expansion = prefix_expansions->a[j];
cat_affix_expansion(key, str, prefix_expansion, token, prefix); cat_affix_expansion(key, str, prefix_expansion, token, prefix, options);
prefix_end = key->n - 1; prefix_end = key->n - 1;
add_space = prefix_expansion.separable && prefix.len < token.len; add_space = prefix_expansion.separable && prefix.len < token.len;
@@ -747,30 +823,24 @@ static void expand_alternative(cstring_array *strings, khash_t(str_set) *unique_
string_tree_t *alternatives; string_tree_t *alternatives;
khiter_t k = kh_get(str_set, unique_strings, new_str); int ret;
log_debug("new_str=%s\n", new_str);
if (k == kh_end(unique_strings)) {
log_debug("Adding alternatives for single normalization\n");
alternatives = add_string_alternatives(new_str, options);
int ret;
k = kh_put(str_set, unique_strings, strdup(new_str), &ret);
if (alternatives == NULL) {
log_debug("alternatives = NULL\n");
}
} else {
if (last_numex_str != NULL) {
free(last_numex_str);
}
continue;
}
log_debug("Adding alternatives for single normalization\n");
alternatives = add_string_alternatives(new_str, options);
if (last_numex_str != NULL) { if (last_numex_str != NULL) {
free(last_numex_str); free(last_numex_str);
} }
if (alternatives == NULL) {
log_debug("alternatives = NULL\n");
continue;
}
iter = string_tree_iterator_new(alternatives); iter = string_tree_iterator_new(alternatives);
log_debug("iter->num_tokens=%d", iter->num_tokens); log_debug("iter->num_tokens=%d\n", iter->num_tokens);
for (; string_tree_iterator_done(iter); string_tree_iterator_next(iter)) { for (; string_tree_iterator_done(iter); string_tree_iterator_next(iter)) {
char_array_clear(temp_string); char_array_clear(temp_string);
@@ -781,7 +851,15 @@ static void expand_alternative(cstring_array *strings, khash_t(str_set) *unique_
char_array_terminate(temp_string); char_array_terminate(temp_string);
token = char_array_get_string(temp_string); token = char_array_get_string(temp_string);
add_postprocessed_string(strings, token, options); log_debug("full string=%s\n", token);
khiter_t k = kh_get(str_set, unique_strings, token);
if (k == kh_end(unique_strings)) {
log_debug("doing postprocessing\n");
add_postprocessed_string(strings, token, options);
k = kh_put(str_set, unique_strings, strdup(token), &ret);
}
} }
@@ -800,13 +878,7 @@ static void expand_alternative(cstring_array *strings, khash_t(str_set) *unique_
char **expand_address(char *input, normalize_options_t options, size_t *n) { char **expand_address(char *input, normalize_options_t options, size_t *n) {
options.address_components |= ADDRESS_ANY; options.address_components |= ADDRESS_ANY;
uint64_t normalize_string_options = 0; uint64_t normalize_string_options = get_normalize_string_options(options);
normalize_string_options |= options.transliterate ? NORMALIZE_STRING_TRANSLITERATE : 0;
normalize_string_options |= options.latin_ascii ? NORMALIZE_STRING_LATIN_ASCII : 0;
normalize_string_options |= options.decompose ? NORMALIZE_STRING_DECOMPOSE : 0;
normalize_string_options |= options.strip_accents ? NORMALIZE_STRING_STRIP_ACCENTS : 0;
normalize_string_options |= options.lowercase ? NORMALIZE_STRING_LOWERCASE : 0;
normalize_string_options |= options.trim_string ? NORMALIZE_STRING_TRIM : 0;
size_t len = strlen(input); size_t len = strlen(input);