On Wednesday 06 November 2002 4:24 pm, Andre Poenitz wrote: > On Wed, Nov 06, 2002 at 04:06:15PM +0000, Angus Leeming wrote: > > The whole point of this exercise was to clean-up the code in biblio.C. As > > a side effect, boost::regex searching now works in the same way as 1.2. > > 95 lines added, 71 removed... I'd like the other way round better...
Ok, this has 73 lines removed and 61 added, many, many of which are comments because none of us are very familiar with boost::regEx. Simple and regex searching with one single algorithm. Ok to apply? Angus
Index: src/frontends/controllers/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/controllers/ChangeLog,v retrieving revision 1.247 diff -u -p -r1.247 ChangeLog --- src/frontends/controllers/ChangeLog 6 Nov 2002 08:56:26 -0000 1.247 +++ src/frontends/controllers/ChangeLog 7 Nov 2002 11:44:30 -0000 @@ -1,5 +1,11 @@ 2002-11-06 Angus Leeming <[EMAIL PROTECTED]> + * biblio.C (searchKeys and helper functions): rewritten entirely + using the STL. Boost::regex searching now works as the old 1.2 code + did. + +2002-11-06 Angus Leeming <[EMAIL PROTECTED]> + * biblio.C: clean-up of the code. No change in functionality. 2002-11-04 Angus Leeming <[EMAIL PROTECTED]> Index: src/frontends/controllers/biblio.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/controllers/biblio.C,v retrieving revision 1.38 diff -u -p -r1.38 biblio.C --- src/frontends/controllers/biblio.C 6 Nov 2002 15:40:12 -0000 1.38 +++ src/frontends/controllers/biblio.C 7 Nov 2002 11:44:31 -0000 @@ -150,7 +150,7 @@ struct compareNoCase: public std::binary return compare_ascii_no_case(s1, s2) < 0; } }; - + } // namespace anon @@ -238,80 +238,51 @@ string const getInfo(InfoMap const & map namespace { -// The functions doing the dirty work for the search. -vector<string>::const_iterator -simpleSearch(InfoMap const & theMap, - vector<string> const & keys, - string const & expr, - vector<string>::const_iterator start, - Direction dir, - bool caseSensitive) +// Escape special chars. +// All characters are literals except: .|*?+(){}[]^$\ +// These characters are literals when preceded by a "\", which is done here +string const escape_special_chars(string const & expr) { - string tmp = expr; - if (!caseSensitive) - tmp = lowercase(tmp); - - vector<string> searchwords = getVectorFromString(tmp, " "); - - // Loop over all keys from start... - for (vector<string>::const_iterator it = start; - // End condition is direction-dependent. - (dir == FORWARD) ? (it<keys.end()) : (it>=keys.begin()); - // increment is direction-dependent. - (dir == FORWARD) ? (++it) : (--it)) { - - string data = (*it); - InfoMap::const_iterator info = theMap.find(*it); - if (info != theMap.end()) - data += " " + info->second; - if (!caseSensitive) - data = lowercase(data); + // Search for all chars .|*?+(){}[]^$\ + // Note that they must be escaped in the RE. + boost::RegEx reg("[\\.\\|\\*\\?\\+\\(\\)\\{\\}\\[\\]\\^\\$\\\\]"); + + // $& is a perl-like expression that expands to all of the current match + // The '$' must be prefixed with the escape character '\' for + // boost to treat it as a literal. + // Thus, to prefix a matched expression with '\', we use: + string const fmt("\\\\$&"); - bool found = true; - - // Loop over all search words... - for (vector<string>::const_iterator sit = searchwords.begin(); - sit != searchwords.end(); ++sit) { - if (data.find(*sit) == string::npos) { - found = false; - break; - } - } - - if (found) return it; - } - - return keys.end(); + return reg.Merge(expr, fmt); } -vector<string>::const_iterator -regexSearch(InfoMap const & theMap, - vector<string> const & keys, - string const & expr, - vector<string>::const_iterator start, - Direction dir) +// A functor for use with std::find_if, used to ascertain whether a +// data entry matches the required regex_ +struct RegexMatch { - boost::regex reg(STRCONV(expr)); - - for (vector<string>::const_iterator it = start; - // End condition is direction-dependent. - (dir == FORWARD) ? (it < keys.end()) : (it >= keys.begin()); - // increment is direction-dependent. - (dir == FORWARD) ? (++it) : (--it)) { - - string data = (*it); - InfoMap::const_iterator info = theMap.find(*it); - if (info != theMap.end()) + // re and icase are used to construct an instance of boost::RegEx. + // if icase is true, then matching is insensitive to case + RegexMatch(InfoMap const & m, string const & re, bool icase) + : map_(m), regex_(re, icase) {} + + bool operator()(string const & key) { + // the data searched is the key + its associated BibTeX/biblio + // fields + string data = key; + InfoMap::const_iterator info = map_.find(key); + if (info != map_.end()) data += " " + info->second; - if (boost::regex_match(STRCONV(data), reg)) { - return it; - } + // Attempts to find a match for the current RE + // somewhere in data. + return regex_.Search(data); } - return keys.end(); -} +private: + InfoMap const map_; + boost::RegEx regex_; +}; } // namespace anon @@ -320,7 +291,7 @@ regexSearch(InfoMap const & theMap, vector<string>::const_iterator searchKeys(InfoMap const & theMap, vector<string> const & keys, - string const & expr, + string const & search_expr, vector<string>::const_iterator start, Search type, Direction dir, @@ -330,15 +301,32 @@ searchKeys(InfoMap const & theMap, if (start < keys.begin() || start >= keys.end()) return keys.end(); - string search_expr = trim(expr); - if (search_expr.empty()) + string expr = trim(search_expr); + if (expr.empty()) return keys.end(); if (type == SIMPLE) - return simpleSearch(theMap, keys, search_expr, start, dir, - caseSensitive); + // We must escape special chars in the search_expr so that + // it is treated as a simple string by boost::regex. + expr = escape_special_chars(expr); + + // Build the functor that will be passed to find_if. + RegexMatch const match(theMap, expr, !caseSensitive); + + // Search the vector of 'keys' from 'start' for one that matches the + // predicate 'match'. Searching can be forward or backward from start. + if (dir == FORWARD) + return std::find_if(start, keys.end(), match); + + vector<string>::const_reverse_iterator rit(start); + vector<string>::const_reverse_iterator rend = keys.rend(); + rit = std::find_if(rit, rend, match); - return regexSearch(theMap, keys, search_expr, start, dir); + if (rit == rend) + return keys.end(); + // This is correct and always safe. + // (See Meyer's Effective STL, Item 28.) + return (++rit).base(); }