Andy Cui
Andy Cui

Reputation: 11

How can I split the string using c++, and then choose the last part of that?

I wanna split a string and then print the number of string, and print the last string inside the delimiter?

std::string s = ">=scott>=tiger>=mushroom>=>=abcd>=";
std::string delimiter = ">=";

size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
    token = s.substr(0, pos);
    std::cout << token << std::endl;
    s.erase(0, pos + delimiter.length());
}
std::cout << s << std::endl;

I wanna calculate the number of the string, and print the last part of this string like this i need print the : 3 abcd

Upvotes: 0

Views: 332

Answers (1)

Hiroki
Hiroki

Reputation: 2880

Edit: I added a minimal solution.


A Minimal Solution

Assuming that I understand the problem correctly, the way I would do it is to define a proper splitting function. Since split empty strings seem to be ignored in your definition of split, I expect that the following splitting function solves the current problem. This function counts the number of non-empty strings and finally create the last non-empty string:

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) };
}

Using this splitting function as follows, we can get the desired output 3 abcd.

DEMO is here.

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;    
}

General Splitting Functions

If other non-empty split strings are also needed, it is desirable to implement a more general splitting function. Also, since general splitting functions would be useful in other problems and thus I think this is a good opportunity to do it. Creating strings in if-section of the above function check and emplacing back it to std::vector, we get a more general splitting function:

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;
}

Using this splitting function as follows, we again get the desired output 3 abcd.

DEMO is here.

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 and std::string_view

Furthermore, in C++17 and over, std::string_view is also available. When std::string_view is created there’s no need to copy the data and it would provide a performance effective method. Thus here I also propose a portable and generic splitting function for both std::string and std::string_view. Using the almost same ctors of std::string and std::string_view, that is

basic_string(const charT* s, size_type n,
             const Allocator& a = Allocator());          

and

constexpr basic_string_view(const charT* str, size_type len);

, and defining the following template function with universal reference

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;
}

, we can split s by delimiter in various ways as follows.

DEMO is here.

// 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);

Upvotes: 1

Related Questions