Move all regex matching to library/string.cpp

This is in preparation to having an option to use std::regex. Also should
fix a few bugs with trace log.
This commit is contained in:
Ilari Liusvaara 2015-02-07 14:37:18 +02:00
parent 94b603c9f2
commit 54cbe456b4
3 changed files with 109 additions and 46 deletions

View file

@ -230,14 +230,33 @@ private:
regex_results regex(const std::string& regex, const std::string& str, const char* ex = NULL)
throw(std::bad_alloc, std::runtime_error);
enum regex_match_mode
{
REGEX_MATCH_REGEX = 0,
REGEX_MATCH_LITERIAL = 1,
REGEX_MATCH_IWILDCARDS = 2,
REGEX_MATCH_IREGEX = 3,
};
/**
* Regexp a string and return match result.
*
* Parameter regex: The regexp to apply.
* Parameter str: The string to apply the regexp to.
* Parameter mode: Match mode.
* 0 => Case-senstive regex (default).
* 1 => Case-insensitive regex.
* 2 =>
* Returns: True if matches, false if not.
*/
bool regex_match(const std::string& regex, const std::string& str) throw(std::bad_alloc, std::runtime_error);
bool regex_match(const std::string& regex, const std::string& str, enum regex_match_mode mode = REGEX_MATCH_REGEX)
throw(std::bad_alloc, std::runtime_error);
/**
* Try match a case-insensitive string fragment and return the result.
*
* \param pattern The pattern to match a
*/
/**
* Cast string to bool.

View file

@ -119,9 +119,78 @@ regex_results regex(const std::string& regexp, const std::string& str, const cha
return regex_results();
}
bool regex_match(const std::string& regexp, const std::string& str) throw(std::bad_alloc, std::runtime_error)
bool regex_match(const std::string& regexp, const std::string& str, enum regex_match_mode mode)
throw(std::bad_alloc, std::runtime_error)
{
return regex(regexp, str);
static threads::lock m;
static std::map<std::string, map_pointer<boost::regex>> regexps;
static std::map<std::pair<regex_match_mode, std::string> , std::pair<std::string, bool>> transform_cache;
std::string _regexp;
bool icase = false;
std::ostringstream y;
{
//See if we have cached transform.
threads::alock h(m);
auto key = std::make_pair(mode, regexp);
if(transform_cache.count(key)) {
auto entry = transform_cache[key];
_regexp = entry.first;
icase = entry.second;
goto transformed;
}
}
switch(mode) {
case REGEX_MATCH_REGEX:
icase = false;
_regexp = regexp;
break;
case REGEX_MATCH_IWILDCARDS:
case REGEX_MATCH_LITERIAL:
for(size_t i = 0; i < regexp.length(); i++)
if(regexp[i] == '?' && mode == REGEX_MATCH_IWILDCARDS)
y << ".";
else if(regexp[i] == '*' && mode == REGEX_MATCH_IWILDCARDS)
y << ".*";
else if(regexp[i] >= 'A' && regexp[i] <= 'Z')
y << regexp[i];
else if(regexp[i] >= 'a' && regexp[i] <= 'z')
y << regexp[i];
else if(regexp[i] >= '0' && regexp[i] <= '9')
y << regexp[i];
else if((unsigned char)regexp[i] > 127) //UTF-8.
y << regexp[i];
else
y << "\\" << regexp[i];
_regexp = ".*" + y.str() + ".*";
icase = true;
break;
case REGEX_MATCH_IREGEX:
icase = true;
_regexp = ".*" + regexp + ".*";
break;
}
transformed:
threads::alock h(m);
auto key = std::make_pair(mode, regexp);
if(!transform_cache.count(key))
transform_cache[key] = std::make_pair(_regexp, icase);
if(!regexps.count(regexp)) {
boost::regex* y = NULL;
auto flags = boost::regex::extended & ~boost::regex::collate;
flags |= boost::regex::nosubs;
if(icase) flags |= boost::regex::icase;
try {
y = new boost::regex(_regexp, flags);
regexps[_regexp] = y;
} catch(std::bad_alloc& e) {
delete y;
throw;
} catch(std::exception& e) {
throw std::runtime_error(e.what());
}
}
return boost::regex_match(str.begin(), str.end(), *(regexps[_regexp]));
}
namespace

View file

@ -845,49 +845,15 @@ namespace
static boost::regex regex;
if(pattern == "")
return false;
if(pattern[0] == 'F') {
//Substring find.
if(pattern != last_find) {
std::string tmp = pattern;
tmp = tmp.substr(1);
regex = boost::regex(tmp, boost::regex_constants::literal |
boost::regex_constants::icase);
last_find = pattern;
}
}
if(pattern[0] == 'W') {
//wildcard find.
if(pattern != last_find) {
std::ostringstream y;
for(size_t i = 1; i < pattern.length(); i++)
if(pattern[i] == '?')
y << ".";
else if(pattern[i] == '*')
y << ".*";
else if(pattern[i] >= 'A' && pattern[i] <= 'Z')
y << pattern[i];
else if(pattern[i] >= 'a' && pattern[i] <= 'z')
y << pattern[i];
else if(pattern[i] >= '0' && pattern[i] <= '9')
y << pattern[i];
else
y << "\\" << pattern[i];
std::string tmp = y.str();
regex = boost::regex(tmp, boost::regex_constants::extended);
last_find = pattern;
}
}
if(pattern[0] == 'R') {
//regexp find.
if(pattern != last_find) {
std::string tmp = pattern;
tmp = tmp.substr(1);
regex = boost::regex(tmp, boost::regex_constants::extended |
boost::regex_constants::icase);
last_find = pattern;
}
}
return regex_search(candidate, regex);
std::string tmp = pattern;
tmp = tmp.substr(1);
if(pattern[0] == 'F')
return regex_match(tmp, candidate, REGEX_MATCH_LITERIAL);
if(pattern[0] == 'W')
return regex_match(tmp, candidate, REGEX_MATCH_IWILDCARDS);
if(pattern[0] == 'R')
return regex_match(tmp, candidate, REGEX_MATCH_IREGEX);
return false;
}
void wxwin_tracelog::on_menu(wxCommandEvent& e)
@ -933,6 +899,15 @@ namespace
find_active = false;
return;
}
//Do syntax check.
try {
find_match(tmp, "");
} catch(...) {
find_active = false;
wxMessageBox(towxstring("Invalid search pattern"), _T("Invalid pattern"),
wxICON_EXCLAMATION | wxOK, this);
return;
}
find_string = tmp;
find_active = true;
find_line = 0;