Reputation: 11
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
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.
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
.
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.
// 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