Мне нужен метод, который помогает мне найти строку внутри другой подстроки или, другими словами, найти строку внутри поддиапазона другой строки. Кроме того, мне нужно найти его в обратном порядке, потому что я знаю, что искомая строка закрыта до конца подстроки, используемой как «стог сена».
Давайте предположим следующий фрагмент кода, где rfind_in_substr
это метод, который я прошу:
std::string sample("An example with the example word example trice");
// substring "ample with the example wo"std::size_t substr_beg = 5;
std::size_t substr_size = 24;
// (1)
std::size_t pos = rfind_in_substr(sample, substr_beg,
substr_size, "example");
// pos == 20, because its the index of the start of the second
// "example" word inside the main string.
Конечно, строка (1) может быть заменена на:
std::size_t pos = substr_beg + sample.substr
(substr_beg, substr_size).rfind("example");
Но это подразумевает ненужную копию подстроки. Есть ли какой-либо метод или метод C ++ / boost, который мог бы помочь мне сделать это?
Я смотрел на boost::algorithm::string
библиотека, но я ничего не нашел (что я понял). Я знаю, что C ++ 17 имеет std::string_view
класс, это было бы идеально, но я использую C ++ 14.
От Boost.StringAlgo:
#include <boost/algorithm/string/find.hpp>
auto haystack = boost::make_iterator_range(str.begin() + from, str.begin() + from + len);
auto found = boost::algorithm::find_last(haystack, needle);
Теперь, если вам нужно использовать это с другими функциями-членами из std::string
, вам нужно сделать дополнительные шаги в преобразовании результирующего диапазона в индекс, как этот ответ делает, но если нет, то просто используйте интерфейс диапазона и избегайте std::string
«полезные» методы.
Другой вариант заключается в использовании boost::string_ref
который является то, что std::string_view
в основном основан на:
#include <iostream>
#include <boost/utility/string_ref.hpp>std::size_t rfind_in_substr(std::string const& str, std::size_t from,
std::size_t len, std::string const& s)
{
return from + boost::string_ref(str).substr(from, len).rfind(s);
}
int main()
{
std::string sample("An example with the example word example trice");
// substring "ample with the example wo"std::size_t substr_beg = 5;
std::size_t substr_size = 24;
// (1)
std::size_t pos = rfind_in_substr(sample, substr_beg,
substr_size, "example");
// pos == 20, because its the index of the start of the second
// "example" word inside the main string.
std::cout << pos << "\n";
}
Вы можете найти ответ, объединив API, который ограничивает поиск в исходной строке по длине, и дополнительную проверку, чтобы увидеть, приходит ли конечный результат до substr_beg
:
std::size_t rfind_in_substr(
const std::string& str
, const std::size_t from
, const std::size_t len
, const std::string& sub
) {
std::size_t res = str.rfind(sub, from+len-sub.size());
return res != string::npos && res >= from ? res : string::npos;
}
from+len-sub.size()
вычисляет последнюю позицию, с которой может начинаться подстрокаres >= from
отклоняет ответ, если он предшествует начальному символу подстроки.С std::find_end
проблему можно решить эффективно, не используя больше, чем нужно, но я надеялся, что найдется какой-нибудь метод, который бы уже решил:
#include <iostream>
#include <string>
#include <algorithm>
std::size_t rfind_in_substr(std::string const& str, std::size_t from,
std::size_t len, std::string const& s)
{
auto sub_beg = str.begin() + from;
auto sub_end = sub_beg + len;
auto found_it = std::find_end(sub_beg, sub_end, s.begin(), s.end());
if (found_it == sub_end)
return str.npos;
else
return found_it - str.begin();
}
int main()
{
std::string sample("An example with the example word example trice");
// substring "ample with the example w"std::size_t substr_beg = 5;
std::size_t substr_size = 24;
std::size_t pos = rfind_in_substr(sample, substr_beg,
substr_size, "example");
std::cout << pos << std::endl; // Prints 20
}