bool Nibbler::getUntilRx (const std::string& regex, std::string& result) { if (_cursor < _length) { RX r (regex, true); std::vector <int> start; std::vector <int> end; if (r.match (start, end, _input->substr (_cursor))) { result = _input->substr (_cursor, start[0]); _cursor += start[0]; } else { result = _input->substr (_cursor); _cursor = _length; } return true; } return false; }
bool Nibbler::skipRx (const std::string& regex) { if (_cursor < _length) { // Regex may be anchored to the beginning and include capturing parentheses, // otherwise they are added. std::string modified_regex; if (regex.substr (0, 2) != "^(") modified_regex = "^(" + regex + ")"; else modified_regex = regex; RX r (modified_regex, true); std::vector <std::string> results; if (r.match (results, _input->substr (_cursor))) { _cursor += results[0].length (); return true; } } return false; }
void Task::substitute ( const std::string& from, const std::string& to, bool global) { // Get the data to modify. std::string description = get ("description"); std::map <std::string, std::string> annotations; getAnnotations (annotations); bool sensitive = context.config.getBoolean ("search.case.sensitive"); // Count the changes, so we know whether to proceed to annotations, after // modifying description. int changes = 0; bool done = false; // Regex support is optional. if (context.config.getBoolean ("regex")) { // Create the regex. RX rx (from, sensitive); std::vector <int> start; std::vector <int> end; // Perform all subs on description. if (rx.match (start, end, description)) { int skew = 0; for (unsigned int i = 0; i < start.size () && !done; ++i) { description.replace (start[i + skew], end[i] - start[i], to); skew += to.length () - (end[i] - start[i]); ++changes; if (!global) done = true; } } if (!done) { // Perform all subs on annotations. std::map <std::string, std::string>::iterator it; for (it = annotations.begin (); it != annotations.end () && !done; ++it) { start.clear (); end.clear (); if (rx.match (start, end, it->second)) { int skew = 0; for (unsigned int i = 0; i < start.size () && !done; ++i) { it->second.replace (start[i + skew], end[i] - start[i], to); skew += to.length () - (end[i] - start[i]); ++changes; if (!global) done = true; } } } } } else { // Perform all subs on description. int counter = 0; std::string::size_type pos = 0; int skew = 0; while ((pos = ::find (description, from, pos, sensitive)) != std::string::npos && !done) { description.replace (pos + skew, from.length (), to); skew += to.length () - from.length (); pos += to.length (); ++changes; if (!global) done = true; if (++counter > APPROACHING_INFINITY) throw format (STRING_INFINITE_LOOP, APPROACHING_INFINITY); } if (!done) { // Perform all subs on annotations. counter = 0; std::map <std::string, std::string>::iterator i; for (i = annotations.begin (); i != annotations.end () && !done; ++i) { pos = 0; skew = 0; while ((pos = ::find (i->second, from, pos, sensitive)) != std::string::npos && !done) { i->second.replace (pos + skew, from.length (), to); skew += to.length () - from.length (); pos += to.length (); ++changes; if (!global) done = true; if (++counter > APPROACHING_INFINITY) throw format (STRING_INFINITE_LOOP, APPROACHING_INFINITY); } } } } if (changes) { set ("description", description); setAnnotations (annotations); recalc_urgency = true; } }