patterncppMinor
Split a character string based on change of character
Viewed 0 times
charactersplitbasedstringchange
Problem
I am contributing a solution to the following task on Rosetta Code:
Task
Split a string into comma (plus a blank) delimited strings based on a change of character (left to right).
Show the output here (use the 1st example below).
Blanks should be treated as any other character (except they are
problematic to display clearly). The same applies to commas.
For instance, the string:
gHHH5YY++///\
should be split and show:
g, HHH, 5, YY, ++, ///, \
Here is the code:
I am fairly new to C++11/14 so any suggestions here will really help.
Task
Split a string into comma (plus a blank) delimited strings based on a change of character (left to right).
Show the output here (use the 1st example below).
Blanks should be treated as any other character (except they are
problematic to display clearly). The same applies to commas.
For instance, the string:
gHHH5YY++///\
should be split and show:
g, HHH, 5, YY, ++, ///, \
Here is the code:
// Solution for http://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character
#include
#include
auto spliter(const std::string &input) {
auto firstCommaPast = false;
std::string res ="";
auto prev = '\0';
for(auto it = input.cbegin(); it != input.cend();++it) {
if(*it!=prev) {
if(!firstCommaPast) {
firstCommaPast = true;
} else {
res+=", ";
}
}
res+=*it;
prev=*it;
}
return res;
}
int main() {
auto input = R"(gHHH5 ))YY++,,,///\)";
std::cout<<spliter(input);
}I am fairly new to C++11/14 so any suggestions here will really help.
Solution
Algorithm
At least at first glance, your algorithm appears to be unnecessarily complex. I'm not entirely sure what
Whitespace
I prefer to see a blank line between the
These don't make any difference to functionality, but fit pretty well with widely accepted practice. I won't try to comment on whether the opening curly brace (
Initialization
Given that it's going to be an empty string either way, I'd rather use
Iterators vs. indexing
The primary reason for using iterators is to support generic algorithms. Using them for a loop outside of a generic algorithm is somewhat questionable. In this case, I see no real improvement over just using an integer type and indexing into the string.
Logic Error
Right now, your code assumes that the first character of a string can't be a
Personally, I think it's easier to initialize
Function Naming
A function does something. As such, its name should normally be a verb, not a noun. Although it may be open to argument whether the best name for what it does is splitting, let's just go with that general idea--in which case its name should be
Resulting Code
Incorporating the elements above, the code could end up something like this:
At least at first glance, your algorithm appears to be unnecessarily complex. I'm not entirely sure what
firstCommaPast is intended to accomplish. It seems to be trying to give some sort of special treatment to commas, even though the directions explicitly state that commas should be treated exactly like any other character.Whitespace
I prefer to see a blank line between the
#includes and other code. I also prefer to see a space between the include and the < or " that follows it:#include
#include
auto spliter(const std::string &input) {These don't make any difference to functionality, but fit pretty well with widely accepted practice. I won't try to comment on whether the opening curly brace (
{) belongs on the same line as the function header, or on the next line by itself. That's widely debated, and I don't think there's any real consensus on which is preferred.Initialization
Given that it's going to be an empty string either way, I'd rather use
std::string res; rather than std::string res="";. The latter will typically add a little extra work without accomplishing anything useful.Iterators vs. indexing
The primary reason for using iterators is to support generic algorithms. Using them for a loop outside of a generic algorithm is somewhat questionable. In this case, I see no real improvement over just using an integer type and indexing into the string.
Logic Error
Right now, your code assumes that the first character of a string can't be a
'\0'. While that's probably at least somewhat unusual, unlike with C strings, it is actually allowed/supported in a std::string (and if it's present, your code won't really work as intended).Personally, I think it's easier to initialize
prev to the first character of the input string, then have the loop proceed from input[1] through the end of the string. This way we don't have to initialize prev to a value that can't be in the string (which is good, because there is no such character).Function Naming
A function does something. As such, its name should normally be a verb, not a noun. Although it may be open to argument whether the best name for what it does is splitting, let's just go with that general idea--in which case its name should be
split, not splitter.Resulting Code
Incorporating the elements above, the code could end up something like this:
#include
#include
auto split(const std::string &input) {
auto prev = input[0];
std::string res{ prev };
for (size_t i = 1; i < input.length(); i++) {
if (input[i] != prev)
res += ", ";
prev = input[i];
res += prev;
}
return res;
}
int main() {
auto input = R"(gHHH5 ))YY++,,,///\)";
std::cout << split(input);
}Code Snippets
#include <string>
#include <iostream>
auto spliter(const std::string &input) {#include <string>
#include <iostream>
auto split(const std::string &input) {
auto prev = input[0];
std::string res{ prev };
for (size_t i = 1; i < input.length(); i++) {
if (input[i] != prev)
res += ", ";
prev = input[i];
res += prev;
}
return res;
}
int main() {
auto input = R"(gHHH5 ))YY++,,,///\)";
std::cout << split(input);
}Context
StackExchange Code Review Q#156282, answer score: 2
Revisions (0)
No revisions yet.