mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-21 22:41:35 +00:00
Dialogue: add conflict resolution for overlapping keywords (Fixes #2245)
This commit is contained in:
parent
c77660ba20
commit
ddd6e682bc
4 changed files with 58 additions and 18 deletions
|
@ -56,13 +56,17 @@ namespace MWDialogue
|
||||||
keywordList.sort(Misc::StringUtils::ciLess);
|
keywordList.sort(Misc::StringUtils::ciLess);
|
||||||
|
|
||||||
KeywordSearch<std::string, int /*unused*/> keywordSearch;
|
KeywordSearch<std::string, int /*unused*/> keywordSearch;
|
||||||
KeywordSearch<std::string, int /*unused*/>::Match match;
|
|
||||||
|
|
||||||
for (std::list<std::string>::const_iterator it = keywordList.begin(); it != keywordList.end(); ++it)
|
for (std::list<std::string>::const_iterator it = keywordList.begin(); it != keywordList.end(); ++it)
|
||||||
keywordSearch.seed(*it, 0 /*unused*/);
|
keywordSearch.seed(*it, 0 /*unused*/);
|
||||||
|
|
||||||
for (std::string::const_iterator it = text.begin(); it != text.end() && keywordSearch.search(it, text.end(), match, text.begin()); it = match.mEnd)
|
std::vector<KeywordSearch<std::string, int /*unused*/>::Match> matches;
|
||||||
tokens.push_back(Token(std::string(match.mBeg, match.mEnd), Token::ImplicitKeyword));
|
keywordSearch.highlightKeywords(text.begin(), text.end(), matches);
|
||||||
|
|
||||||
|
for (std::vector<KeywordSearch<std::string, int /*unused*/>::Match>::const_iterator it = matches.begin(); it != matches.end(); ++it)
|
||||||
|
{
|
||||||
|
tokens.push_back(Token(std::string(it->mBeg, it->mEnd), Token::ImplicitKeyword));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t removePseudoAsterisks(std::string & phrase)
|
size_t removePseudoAsterisks(std::string & phrase)
|
||||||
|
|
|
@ -66,12 +66,12 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool search (Point beg, Point end, Match & match, Point start)
|
void highlightKeywords (Point beg, Point end, std::vector<Match>& out)
|
||||||
{
|
{
|
||||||
for (Point i = beg; i != end; ++i)
|
for (Point i = beg; i != end; ++i)
|
||||||
{
|
{
|
||||||
// check if previous character marked start of new word
|
// check if previous character marked start of new word
|
||||||
if (i != start)
|
if (i != beg)
|
||||||
{
|
{
|
||||||
Point prev = i;
|
Point prev = i;
|
||||||
--prev;
|
--prev;
|
||||||
|
@ -79,6 +79,7 @@ public:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check first character
|
// check first character
|
||||||
typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale));
|
typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale));
|
||||||
|
|
||||||
|
@ -137,16 +138,48 @@ public:
|
||||||
if (t != candidate->second.mKeyword.end ())
|
if (t != candidate->second.mKeyword.end ())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// we did it, report the good news
|
// found a keyword, but there might still be longer keywords that start somewhere _within_ this keyword
|
||||||
|
// we will resolve these overlapping keywords later, choosing the longest one in case of conflict
|
||||||
|
Match match;
|
||||||
match.mValue = candidate->second.mValue;
|
match.mValue = candidate->second.mValue;
|
||||||
match.mBeg = i;
|
match.mBeg = i;
|
||||||
match.mEnd = k;
|
match.mEnd = k;
|
||||||
return true;
|
out.push_back(match);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no match in range, report the bad news
|
// resolve overlapping keywords
|
||||||
return false;
|
for (typename std::vector<Match>::iterator it = out.begin(); it != out.end();)
|
||||||
|
{
|
||||||
|
typename std::vector<Match>::iterator next = it;
|
||||||
|
++next;
|
||||||
|
|
||||||
|
if (next == out.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (it->mEnd <= next->mBeg)
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
continue; // no overlap
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// prefer the longer keyword
|
||||||
|
int size = it->mEnd - it->mBeg;
|
||||||
|
int nextSize = next->mEnd - next->mBeg;
|
||||||
|
if (size >= nextSize) // if both are the same length, then prefer the first keyword
|
||||||
|
{
|
||||||
|
out.erase(next);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it = out.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -177,11 +177,13 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string::const_iterator i = text.begin ();
|
std::vector<KeywordSearchT::Match> matches;
|
||||||
KeywordSearchT::Match match;
|
keywordSearch->highlightKeywords(text.begin(), text.end(), matches);
|
||||||
|
|
||||||
while (i != text.end () && keywordSearch->search (i, text.end (), match, text.begin ()))
|
std::string::const_iterator i = text.begin ();
|
||||||
|
for (std::vector<KeywordSearchT::Match>::iterator it = matches.begin(); it != matches.end(); ++it)
|
||||||
{
|
{
|
||||||
|
KeywordSearchT::Match match = *it;
|
||||||
if (i != match.mBeg)
|
if (i != match.mBeg)
|
||||||
addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ());
|
addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ());
|
||||||
|
|
||||||
|
@ -189,7 +191,6 @@ namespace MWGui
|
||||||
|
|
||||||
i = match.mEnd;
|
i = match.mEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != text.end ())
|
if (i != text.end ())
|
||||||
addTopicLink (typesetter, 0, i - text.begin (), text.size ());
|
addTopicLink (typesetter, 0, i - text.begin (), text.size ());
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,12 +174,14 @@ struct JournalViewModelImpl : JournalViewModel
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
std::vector<KeywordSearchT::Match> matches;
|
||||||
|
mModel->mKeywordSearch.highlightKeywords(utf8text.begin(), utf8text.end(), matches);
|
||||||
|
|
||||||
std::string::const_iterator i = utf8text.begin ();
|
std::string::const_iterator i = utf8text.begin ();
|
||||||
|
for (std::vector<KeywordSearchT::Match>::const_iterator it = matches.begin(); it != matches.end(); ++it)
|
||||||
KeywordSearchT::Match match;
|
|
||||||
|
|
||||||
while (i != utf8text.end () && mModel->mKeywordSearch.search (i, utf8text.end (), match, utf8text.begin()))
|
|
||||||
{
|
{
|
||||||
|
const KeywordSearchT::Match& match = *it;
|
||||||
|
|
||||||
if (i != match.mBeg)
|
if (i != match.mBeg)
|
||||||
visitor (0, i - utf8text.begin (), match.mBeg - utf8text.begin ());
|
visitor (0, i - utf8text.begin (), match.mBeg - utf8text.begin ());
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue