summaryrefslogtreecommitdiff
path: root/libs/hunspell/src/suggestmgr.c++
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hunspell/src/suggestmgr.c++')
-rw-r--r--libs/hunspell/src/suggestmgr.c++294
1 files changed, 199 insertions, 95 deletions
diff --git a/libs/hunspell/src/suggestmgr.c++ b/libs/hunspell/src/suggestmgr.c++
index 73ea91e3a3..6b363debd5 100644
--- a/libs/hunspell/src/suggestmgr.c++
+++ b/libs/hunspell/src/suggestmgr.c++
@@ -1,7 +1,7 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
- * Copyright (C) 2002-2017 Németh László
+ * Copyright (C) 2002-2022 Németh László
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
@@ -72,6 +72,7 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
+#include <time.h>
#include "suggestmgr.hxx"
#include "htypes.hxx"
@@ -79,6 +80,8 @@
const w_char W_VLINE = {'\0', '|'};
+#define MAX_CHAR_DISTANCE 4
+
SuggestMgr::SuggestMgr(const char* tryme, unsigned int maxn, AffixMgr* aptr) {
// register affix manager and check in string of chars to
// try when building candidate suggestions
@@ -132,6 +135,11 @@ SuggestMgr::SuggestMgr(const char* tryme, unsigned int maxn, AffixMgr* aptr) {
ctryl = u8_u16(ctry_utf, tryme);
}
}
+
+ // language with possible dash usage
+ // (latin letters or dash in TRY characters)
+ lang_with_dash_usage = (ctry &&
+ ((strchr(ctry, '-') != NULL) || (strchr(ctry, 'a') != NULL)));
}
SuggestMgr::~SuggestMgr() {
@@ -169,10 +177,13 @@ void SuggestMgr::testsug(std::vector<std::string>& wlst,
}
}
-// generate suggestions for a misspelled word
-// pass in address of array of char * pointers
-// onlycompoundsug: probably bad suggestions (need for ngram sugs, too)
-void SuggestMgr::suggest(std::vector<std::string>& slst,
+/* generate suggestions for a misspelled word
+ * pass in address of array of char * pointers
+ * onlycompoundsug: probably bad suggestions (need for ngram sugs, too)
+ * return value: true, if there is a good suggestion
+ * (REP, ph: or a dictionary word pair)
+ */
+bool SuggestMgr::suggest(std::vector<std::string>& slst,
const char* w,
int* onlycompoundsug) {
int nocompoundtwowords = 0;
@@ -182,6 +193,7 @@ void SuggestMgr::suggest(std::vector<std::string>& slst,
std::string w2;
const char* word = w;
size_t oldSug = 0;
+ bool good_suggestion = false;
// word reversing wrapper for complex prefixes
if (complexprefixes) {
@@ -196,34 +208,49 @@ void SuggestMgr::suggest(std::vector<std::string>& slst,
if (utf8) {
wl = u8_u16(word_utf, word);
if (wl == -1) {
- return;
+ return false;
}
}
- for (int cpdsuggest = 0; (cpdsuggest < 2) && (nocompoundtwowords == 0);
+ for (int cpdsuggest = 0; (cpdsuggest < 2) && (nocompoundtwowords == 0) && !good_suggestion;
cpdsuggest++) {
+
+ clock_t timelimit;
+ // initialize both in non-compound and compound cycles
+ timelimit = clock();
+
// limit compound suggestion
if (cpdsuggest > 0)
oldSug = slst.size();
// suggestions for an uppercase word (html -> HTML)
if (slst.size() < maxSug) {
+ size_t i = slst.size();
if (utf8)
- capchars_utf(slst, &word_utf[0], wl, cpdsuggest);
+ capchars_utf(slst, word_utf.data(), wl, cpdsuggest);
else
capchars(slst, word, cpdsuggest);
+ if (slst.size() > i)
+ good_suggestion = true;
}
// perhaps we made a typical fault of spelling
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
+ size_t i = slst.size();
replchars(slst, word, cpdsuggest);
+ if (slst.size() > i)
+ good_suggestion = true;
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// perhaps we made chose the wrong char from a related set
if ((slst.size() < maxSug) &&
(!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
mapchars(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// only suggest compound words when no other suggestion
if ((cpdsuggest == 0) && (slst.size() > nsugorig))
@@ -232,77 +259,99 @@ void SuggestMgr::suggest(std::vector<std::string>& slst,
// did we swap the order of chars by mistake
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- swapchar_utf(slst, &word_utf[0], wl, cpdsuggest);
+ swapchar_utf(slst, word_utf.data(), wl, cpdsuggest);
else
swapchar(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// did we swap the order of non adjacent chars by mistake
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- longswapchar_utf(slst, &word_utf[0], wl, cpdsuggest);
+ longswapchar_utf(slst, word_utf.data(), wl, cpdsuggest);
else
longswapchar(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// did we just hit the wrong key in place of a good char (case and keyboard)
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- badcharkey_utf(slst, &word_utf[0], wl, cpdsuggest);
+ badcharkey_utf(slst, word_utf.data(), wl, cpdsuggest);
else
badcharkey(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// did we add a char that should not be there
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- extrachar_utf(slst, &word_utf[0], wl, cpdsuggest);
+ extrachar_utf(slst, word_utf.data(), wl, cpdsuggest);
else
extrachar(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// did we forgot a char
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- forgotchar_utf(slst, &word_utf[0], wl, cpdsuggest);
+ forgotchar_utf(slst, word_utf.data(), wl, cpdsuggest);
else
forgotchar(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// did we move a char
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- movechar_utf(slst, &word_utf[0], wl, cpdsuggest);
+ movechar_utf(slst, word_utf.data(), wl, cpdsuggest);
else
movechar(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// did we just hit the wrong key in place of a good char
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- badchar_utf(slst, &word_utf[0], wl, cpdsuggest);
+ badchar_utf(slst, word_utf.data(), wl, cpdsuggest);
else
badchar(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// did we double two characters
if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
if (utf8)
- doubletwochars_utf(slst, &word_utf[0], wl, cpdsuggest);
+ doubletwochars_utf(slst, word_utf.data(), wl, cpdsuggest);
else
doubletwochars(slst, word, cpdsuggest);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
// perhaps we forgot to hit space and two words ran together
- if (!nosplitsugs && (slst.size() < maxSug) &&
- (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) {
- twowords(slst, word, cpdsuggest);
+ // (dictionary word pairs have top priority here, so
+ // we always suggest them, in despite of nosplitsugs, and
+ // drop compound word and other suggestions)
+ if (!cpdsuggest || (!nosplitsugs && slst.size() < oldSug + maxcpdsugs)) {
+ good_suggestion = twowords(slst, word, cpdsuggest, good_suggestion);
}
+ if (clock() > timelimit + TIMELIMIT_SUGGESTION)
+ return good_suggestion;
} // repeating ``for'' statement compounding support
if (!nocompoundtwowords && (!slst.empty()) && onlycompoundsug)
*onlycompoundsug = 1;
+
+ return good_suggestion;
}
// suggestions for an uppercase word (html -> HTML)
@@ -450,8 +499,11 @@ int SuggestMgr::replchars(std::vector<std::string>& wlst,
return wlst.size();
}
-// perhaps we doubled two characters (pattern aba -> ababa, for example vacation
-// -> vacacation)
+// perhaps we doubled two characters
+// (for example vacation -> vacacation)
+// The recognized pattern with regex back-references:
+// "(.)(.)\1\2\1" or "..(.)(.)\1\2"
+
int SuggestMgr::doubletwochars(std::vector<std::string>& wlst,
const char* word,
int cpdsuggest) {
@@ -462,7 +514,7 @@ int SuggestMgr::doubletwochars(std::vector<std::string>& wlst,
for (int i = 2; i < wl; i++) {
if (word[i] == word[i - 2]) {
state++;
- if (state == 3) {
+ if (state == 3 || (state == 2 && i >= 4)) {
std::string candidate(word, word + i - 1);
candidate.insert(candidate.end(), word + i + 1, word + wl);
testsug(wlst, candidate, cpdsuggest, NULL, NULL);
@@ -475,8 +527,11 @@ int SuggestMgr::doubletwochars(std::vector<std::string>& wlst,
return wlst.size();
}
-// perhaps we doubled two characters (pattern aba -> ababa, for example vacation
-// -> vacacation)
+// perhaps we doubled two characters
+// (for example vacation -> vacacation)
+// The recognized pattern with regex back-references:
+// "(.)(.)\1\2\1" or "..(.)(.)\1\2"
+
int SuggestMgr::doubletwochars_utf(std::vector<std::string>& wlst,
const w_char* word,
int wl,
@@ -487,7 +542,7 @@ int SuggestMgr::doubletwochars_utf(std::vector<std::string>& wlst,
for (int i = 2; i < wl; i++) {
if (word[i] == word[i - 2]) {
state++;
- if (state == 3) {
+ if (state == 3 || (state == 2 && i >= 4)) {
std::vector<w_char> candidate_utf(word, word + i - 1);
candidate_utf.insert(candidate_utf.end(), word + i + 1, word + wl);
std::string candidate;
@@ -721,17 +776,22 @@ int SuggestMgr::forgotchar_utf(std::vector<std::string>& wlst,
return wlst.size();
}
-/* error is should have been two words */
-int SuggestMgr::twowords(std::vector<std::string>& wlst,
+/* error is should have been two words
+ * return value is true, if there is a dictionary word pair,
+ * or there was already a good suggestion before calling
+ * this function.
+ */
+bool SuggestMgr::twowords(std::vector<std::string>& wlst,
const char* word,
- int cpdsuggest) {
+ int cpdsuggest,
+ bool good) {
int c2;
int forbidden = 0;
int cwrd;
int wl = strlen(word);
if (wl < 3)
- return wlst.size();
+ return false;
if (langnum == LANG_hu)
forbidden = check_forbidden(word, wl);
@@ -750,63 +810,87 @@ int SuggestMgr::twowords(std::vector<std::string>& wlst,
}
if (utf8 && p[1] == '\0')
break; // last UTF-8 character
- *p = '\0';
- int c1 = checkword(candidate, cpdsuggest, NULL, NULL);
- if (c1) {
- c2 = checkword((p + 1), cpdsuggest, NULL, NULL);
- if (c2) {
- *p = ' ';
-
- // spec. Hungarian code (need a better compound word support)
- if ((langnum == LANG_hu) && !forbidden &&
- // if 3 repeating letter, use - instead of space
- (((p[-1] == p[1]) &&
- (((p > candidate + 1) && (p[-1] == p[-2])) || (p[-1] == p[2]))) ||
- // or multiple compounding, with more, than 6 syllables
- ((c1 == 3) && (c2 >= 2))))
- *p = '-';
-
- cwrd = 1;
- for (size_t k = 0; k < wlst.size(); ++k) {
- if (wlst[k] == candidate) {
- cwrd = 0;
- break;
- }
- }
- if (wlst.size() < maxSug) {
- if (cwrd) {
- wlst.push_back(candidate);
- }
- } else {
- free(candidate);
- return wlst.size();
+
+ // Suggest only word pairs, if they are listed in the dictionary.
+ // For example, adding "a lot" to the English dic file will
+ // result only "alot" -> "a lot" suggestion instead of
+ // "alto, slot, alt, lot, allot, aloft, aloe, clot, plot, blot, a lot".
+ // Note: using "ph:alot" keeps the other suggestions:
+ // a lot ph:alot
+ // alot -> a lot, alto, slot...
+ *p = ' ';
+ if (!cpdsuggest && checkword(candidate, cpdsuggest, NULL, NULL)) {
+ // remove not word pair suggestions
+ if (!good) {
+ good = true;
+ wlst.clear();
+ }
+ wlst.insert(wlst.begin(), candidate);
+ }
+
+ // word pairs with dash?
+ if (lang_with_dash_usage) {
+ *p = '-';
+
+ if (!cpdsuggest && checkword(candidate, cpdsuggest, NULL, NULL)) {
+ // remove not word pair suggestions
+ if (!good) {
+ good = true;
+ wlst.clear();
}
- // add two word suggestion with dash, if TRY string contains
- // "a" or "-"
- // NOTE: cwrd doesn't modified for REP twoword sugg.
- if (ctry && (strchr(ctry, 'a') || strchr(ctry, '-')) &&
- mystrlen(p + 1) > 1 && mystrlen(candidate) - mystrlen(p) > 1) {
- *p = '-';
+ wlst.insert(wlst.begin(), candidate);
+ }
+ }
+
+ if (wlst.size() < maxSug && !nosplitsugs && !good) {
+ *p = '\0';
+ int c1 = checkword(candidate, cpdsuggest, NULL, NULL);
+ if (c1) {
+ c2 = checkword((p + 1), cpdsuggest, NULL, NULL);
+ if (c2) {
+ // spec. Hungarian code (TODO need a better compound word support)
+ if ((langnum == LANG_hu) && !forbidden &&
+ // if 3 repeating letter, use - instead of space
+ (((p[-1] == p[1]) &&
+ (((p > candidate + 1) && (p[-1] == p[-2])) || (p[-1] == p[2]))) ||
+ // or multiple compounding, with more, than 6 syllables
+ ((c1 == 3) && (c2 >= 2))))
+ *p = '-';
+ else
+ *p = ' ';
+
+ cwrd = 1;
for (size_t k = 0; k < wlst.size(); ++k) {
if (wlst[k] == candidate) {
cwrd = 0;
break;
}
}
- if (wlst.size() < maxSug) {
- if (cwrd) {
+
+ if (cwrd && (wlst.size() < maxSug))
wlst.push_back(candidate);
+
+ // add two word suggestion with dash, depending on the language
+ // Note that cwrd doesn't modified for REP twoword sugg.
+ if ( !nosplitsugs && lang_with_dash_usage &&
+ mystrlen(p + 1) > 1 && mystrlen(candidate) - mystrlen(p) > 1) {
+ *p = '-';
+ for (size_t k = 0; k < wlst.size(); ++k) {
+ if (wlst[k] == candidate) {
+ cwrd = 0;
+ break;
+ }
}
- } else {
- free(candidate);
- return wlst.size();
+
+ if ((wlst.size() < maxSug) && cwrd)
+ wlst.push_back(candidate);
}
}
}
}
}
free(candidate);
- return wlst.size();
+ return good;
}
// error is adjacent letter were swapped
@@ -891,7 +975,8 @@ int SuggestMgr::longswapchar(std::vector<std::string>& wlst,
// try swapping not adjacent chars one by one
for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) {
for (std::string::iterator q = candidate.begin(); q < candidate.end(); ++q) {
- if (std::abs(std::distance(q, p)) > 1) {
+ size_t distance = std::abs(std::distance(q, p));
+ if (distance > 1 && distance <= MAX_CHAR_DISTANCE) {
std::swap(*p, *q);
testsug(wlst, candidate, cpdsuggest, NULL, NULL);
std::swap(*p, *q);
@@ -910,7 +995,8 @@ int SuggestMgr::longswapchar_utf(std::vector<std::string>& wlst,
// try swapping not adjacent chars
for (std::vector<w_char>::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) {
for (std::vector<w_char>::iterator q = candidate_utf.begin(); q < candidate_utf.end(); ++q) {
- if (std::abs(std::distance(q, p)) > 1) {
+ size_t distance = std::abs(std::distance(q, p));
+ if (distance > 1 && distance <= MAX_CHAR_DISTANCE) {
std::swap(*p, *q);
std::string candidate;
u16_u8(candidate, candidate_utf);
@@ -932,7 +1018,7 @@ int SuggestMgr::movechar(std::vector<std::string>& wlst,
// try moving a char
for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) {
- for (std::string::iterator q = p + 1; q < candidate.end() && std::distance(p, q) < 10; ++q) {
+ for (std::string::iterator q = p + 1; q < candidate.end() && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++q) {
std::swap(*q, *(q - 1));
if (std::distance(p, q) < 2)
continue; // omit swap char
@@ -942,7 +1028,7 @@ int SuggestMgr::movechar(std::vector<std::string>& wlst,
}
for (std::string::reverse_iterator p = candidate.rbegin(), pEnd = candidate.rend() - 1; p != pEnd; ++p) {
- for (std::string::reverse_iterator q = p + 1, qEnd = candidate.rend(); q != qEnd && std::distance(p, q) < 10; ++q) {
+ for (std::string::reverse_iterator q = p + 1, qEnd = candidate.rend(); q != qEnd && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++q) {
std::swap(*q, *(q - 1));
if (std::distance(p, q) < 2)
continue; // omit swap char
@@ -965,7 +1051,7 @@ int SuggestMgr::movechar_utf(std::vector<std::string>& wlst,
// try moving a char
for (std::vector<w_char>::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) {
- for (std::vector<w_char>::iterator q = p + 1; q < candidate_utf.end() && std::distance(p, q) < 10; ++q) {
+ for (std::vector<w_char>::iterator q = p + 1; q < candidate_utf.end() && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++q) {
std::swap(*q, *(q - 1));
if (std::distance(p, q) < 2)
continue; // omit swap char
@@ -977,7 +1063,7 @@ int SuggestMgr::movechar_utf(std::vector<std::string>& wlst,
}
for (std::vector<w_char>::reverse_iterator p = candidate_utf.rbegin(); p < candidate_utf.rend(); ++p) {
- for (std::vector<w_char>::reverse_iterator q = p + 1; q < candidate_utf.rend() && std::distance(p, q) < 10; ++q) {
+ for (std::vector<w_char>::reverse_iterator q = p + 1; q < candidate_utf.rend() && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++q) {
std::swap(*q, *(q - 1));
if (std::distance(p, q) < 2)
continue; // omit swap char
@@ -994,7 +1080,8 @@ int SuggestMgr::movechar_utf(std::vector<std::string>& wlst,
// generate a set of suggestions for very poorly spelled words
void SuggestMgr::ngsuggest(std::vector<std::string>& wlst,
const char* w,
- const std::vector<HashMgr*>& rHMgr) {
+ const std::vector<HashMgr*>& rHMgr,
+ int captype) {
int lval;
int sc;
int lp, lpphon;
@@ -1071,18 +1158,34 @@ void SuggestMgr::ngsuggest(std::vector<std::string>& wlst,
u8_u16(w_word, word);
u8_u16(w_target, target);
}
-
+
std::string f;
std::vector<w_char> w_f;
-
+
for (size_t i = 0; i < rHMgr.size(); ++i) {
while (0 != (hp = rHMgr[i]->walk_hashtable(col, hp))) {
- if ((hp->astr) && (pAMgr) &&
- (TESTAFF(hp->astr, forbiddenword, hp->alen) ||
- TESTAFF(hp->astr, ONLYUPCASEFLAG, hp->alen) ||
- TESTAFF(hp->astr, nosuggest, hp->alen) ||
- TESTAFF(hp->astr, nongramsuggest, hp->alen) ||
- TESTAFF(hp->astr, onlyincompound, hp->alen)))
+ // skip exceptions
+ if (
+ // skip it, if the word length different by 5 or
+ // more characters (to avoid strange suggestions)
+ // (except Unicode characters over BMP)
+ (((abs(n - hp->clen) > 4) && !nonbmp)) ||
+ // don't suggest capitalized dictionary words for
+ // lower case misspellings in ngram suggestions, except
+ // - PHONE usage, or
+ // - in the case of German, where not only proper
+ // nouns are capitalized, or
+ // - the capitalized word has special pronunciation
+ ((captype == NOCAP) && (hp->var & H_OPT_INITCAP) &&
+ !ph && (langnum != LANG_de) && !(hp->var & H_OPT_PHON)) ||
+ // or it has one of the following special flags
+ ((hp->astr) && (pAMgr) &&
+ (TESTAFF(hp->astr, forbiddenword, hp->alen) ||
+ TESTAFF(hp->astr, ONLYUPCASEFLAG, hp->alen) ||
+ TESTAFF(hp->astr, nosuggest, hp->alen) ||
+ TESTAFF(hp->astr, nongramsuggest, hp->alen) ||
+ TESTAFF(hp->astr, onlyincompound, hp->alen)))
+ )
continue;
if (utf8) {
@@ -1105,7 +1208,7 @@ void SuggestMgr::ngsuggest(std::vector<std::string>& wlst,
sc = ngram(3, word, f, NGRAM_LONGER_WORSE) + leftcommon;
}
- // check special pronounciation
+ // check special pronunciation
f.clear();
if ((hp->var & H_OPT_PHON) &&
copy_field(f, HENTRY_DATA(hp), MORPH_PHON)) {
@@ -1559,7 +1662,8 @@ int SuggestMgr::checkword(const std::string& word,
if (rv) {
if ((rv->astr) &&
(TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) ||
- TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen)))
+ TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen) ||
+ TESTAFF(rv->astr, pAMgr->get_substandard(), rv->alen)))
return 0;
while (rv) {
if (rv->astr &&
@@ -1584,7 +1688,7 @@ int SuggestMgr::checkword(const std::string& word,
if (!rv && pAMgr->have_contclass()) {
rv = pAMgr->suffix_check_twosfx(word.c_str(), word.size(), 0, NULL, FLAG_NULL);
if (!rv)
- rv = pAMgr->prefix_check_twosfx(word.c_str(), word.size(), 1, FLAG_NULL);
+ rv = pAMgr->prefix_check_twosfx(word.c_str(), word.size(), 0, FLAG_NULL);
}
// check forbidden words
@@ -1649,15 +1753,15 @@ std::string SuggestMgr::suggest_morph(const std::string& in_w) {
TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) ||
TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) {
if (!HENTRY_FIND(rv, MORPH_STEM)) {
- result.append(" ");
+ result.push_back(MSEP_FLD);
result.append(MORPH_STEM);
result.append(w);
}
if (HENTRY_DATA(rv)) {
- result.append(" ");
+ result.push_back(MSEP_FLD);
result.append(HENTRY_DATA2(rv));
}
- result.append("\n");
+ result.push_back(MSEP_REC);
}
rv = rv->next_homonym;
}
@@ -1713,7 +1817,7 @@ std::string SuggestMgr::suggest_hentry_gen(hentry* rv, const char* pattern) {
HENTRY_DATA(rv), pattern, 0);
if (!aff.empty()) {
result.append(aff);
- result.append("\n");
+ result.push_back(MSEP_REC);
}
}
@@ -1737,7 +1841,7 @@ std::string SuggestMgr::suggest_hentry_gen(hentry* rv, const char* pattern) {
rv2->alen, HENTRY_DATA(rv2), pattern, 0);
if (!aff.empty()) {
result.append(aff);
- result.append("\n");
+ result.push_back(MSEP_REC);
}
}
}
@@ -1936,7 +2040,7 @@ int SuggestMgr::leftcommonsubstring(
int l2 = su2.size();
// decapitalize dictionary word
if (complexprefixes) {
- if (su1[l1 - 1] == su2[l2 - 1])
+ if (l1 && l2 && su1[l1 - 1] == su2[l2 - 1])
return 1;
} else {
unsigned short idx = su2.empty() ? 0 : (su2[0].h << 8) + su2[0].l;