Редактировать : я добавил минимальное решение.
Минимальное решение
Предполагая, что я правильно понимаю проблему,Я бы сделал так, чтобы определить правильную функцию расщепления.Поскольку в вашем определении split кажется, что разделенные пустые строки игнорируются, я ожидаю, что следующая функция разделения решает текущую проблему.Эта функция считает количество непустых строк и, наконец, создает последнюю непустую строку:
std::pair<std::size_t, std::string>
check(const std::string& str, const std::string& delimiter)
{
std::size_t count = 0;
auto begin = str.begin();
auto end = str.begin();
for(auto it = str.begin();
it != str.cend();
it += ((it == str.cend()) ? 0 : delimiter.length()) )
{
const auto preit = it;
it = std::search(preit, str.cend(), delimiter.cbegin(), delimiter.cend());
if(it != preit)
{
++count;
begin = preit;
end = it;
}
}
return { count, std::string(begin, end) };
}
Используя эту функцию разделения следующим образом, мы можем получить желаемый результат 3 abcd.
ДЕМО здесь.
std::string s = ">=scott>=tiger>=mushroom>=>=abcd>=";
std::string delimiter = ">=";
const auto result = check(s, delimiter);
if(result.first != 0){
std::cout << (result.first - 1) << " " << result.second << std::endl;
}
Общие функции разделения
Если другое непустое разделениеСтроки также необходимы, желательно реализовать более общую функцию расщепления.Кроме того, поскольку общие функции расщепления были бы полезны в других задачах, и поэтому я думаю, что это хорошая возможность сделать это.Создавая строки в секции if вышеуказанной функции check
и возвращая ее в std::vector
, мы получаем более общую функцию расщепления:
std::vector<std::string>
split(const std::string& str, const std::string& delimiter)
{
std::vector<std::string> strings;
for(auto it = str.begin();
it != str.cend();
it += ((it == str.cend()) ? 0 : delimiter.length()) )
{
const auto preit = it;
it = std::search(preit, str.cend(), delimiter.cbegin(), delimiter.cend());
if(it != preit){
strings.emplace_back(preit, it);
}
}
return strings;
}
Используя эту функцию расщепления следующим образом, мы снова получаемжелаемый вывод 3 abcd
.
DEMO здесь.
std::string s = ">=scott>=tiger>=mushroom>=>=abcd>=";
std::string delimiter = ">=";
const auto strings = split(s, delimiter);
if(!strings.empty()){
std::cout << (strings.size() - 1) << " " << strings.back() << std::endl;
}
C ++ 17 и std::string_view
Кроме того, в C ++ 17 и более, std::string_view
также доступна.Когда создается std::string_view
, нет необходимости копировать данные, и это обеспечит эффективный метод.Таким образом, здесь я также предлагаю переносимую и универсальную функцию разделения для std::string
и std::string_view
.Используя почти одинаковые ctors std::string
и std::string_view
, то есть
basic_string(const charT* s, size_type n,
const Allocator& a = Allocator());
и
constexpr basic_string_view(const charT* str, size_type len);
и определяяСледующая функция шаблона с универсальной ссылкой
template<typename C>
auto split(C&& str, const std::string& delimiter)
{
std::vector<typename std::remove_reference<C>::type> strings;
for (auto p = str.data(), end = p + str.length();
p != end;
p += ((p==end) ? 0 : delimiter.length()) )
{
const auto pre = p;
p = std::search(pre, end, delimiter.cbegin(), delimiter.cend());
if (p != pre)
{
strings.emplace_back(pre, p - pre);
}
}
return strings;
}
, мы можем разделить s
на delimiter
различными способами следующим образом.
DEMO здесь.
// std::string_view
const auto strings = split<std::string_view>(s, delimiter);
// std::string(s: lvalue reference)
const auto strings = split(s, delimiter);
// std::string(s: rvalue)
const auto strings = split(std::move(s), delimiter);