Below is a loop to replace consecutive __ with _ in a string (Name and Identity are std::strings's).
for(std::string::const_iterator it=Name.begin(); it!= Name.end(); it)
Identity = (*it == '_' && *std::next(it, 1) == '_')?21:*it;
21 represents negative acknowledge in the ASCII table (tried returning others too like 0, '\0', leaving the return when true empty). But when this string is written to a text file there is a special character in place of the extra _ like so b0^U_fifo(where ^U is in place of the duplicate _ I am trying to remove).
How does one return a "nothing" char?
CodePudding user response:
How does one return a "nothing" char?
One doesn't return a "nothing" char since such char doesn't exist.
Instead of trying to insert a "nothing" char, you should probably be "not inserting" a char. Perhaps something like this:
if (*it != '_' || *std::next(it, 1) != '_')
Identity = *it;
CodePudding user response:
Don't let them tell you not to use the ternary operator. It is perfectly fine. You want to do branchless programming :-)
With std::pair
std::string temp(Name.length(), '\0');
std::string::iterator tit = temp.begin();
for(std::string::const_iterator it = Name.begin(); it != Name.end(); it)
std::tie(tit, *tit) = make_pair(*it == '_' && std::next(it, 1) != Name.end() && *std::next(it, 1) == '_' ?
tit : tit 1, *it);
std::string Identity(temp.begin(), tit);
or joking use of ternary operator:
std::string Identity;
for(std::string::const_iterator it = Name.begin(); it!= Name.end(); it)
*it == '_' && std::next(it, 1) != Name.end() && *std::next(it, 1) == '_' ?
std::string() : Identity = *it;
or more serious use of ternary operator:
std::string Identity;
for(std::string::const_iterator it = Name.begin(); it!= Name.end(); it)
Identity = (*it == '_' && std::next(it, 1) != Name.end() && *std::next(it, 1) == '_') ?
std::string() : std::string(1, *it);
Edit: Additional check to prevent dereferencing Name.end()
CodePudding user response:
to replace consecutive __ with _
The problem is that the string to be replaced and the replacement differ in length – still you are lucky as the replacement string is shorter than what it replaces, thus you won't need to re-allocate any memory.
Now when you replace a double underscore with a single one there remains a gap. Instead of trying to fill it with some dummy value you might rather move the subsequent characters towards the end of the resulting string, which might look as follows (in-place replacement within the string, i. e. you don't enforce creation of a copy if this is not necessary):
if(!theString.empty())
{
auto pos = theString.begin();
for(auto cur = std::next(pos); cur != theString.end(); cur)
{
if(*cur != '_' || *pos != '_')
{
* pos = *cur;
}
}
theString.resize(std::distance(theString.begin(), pos) 1);
}
Note that this replaces longer sequences of underscores with a single one as well. If this is not intended the loop needs some adjustments, but the basic idea remains the same.
CodePudding user response:
I would use a find() substr() loop, eg:
string::size_type start = 0, end;
while ((end = Name.find("__", start)) != std::string::npos)
{
Identity = Name.substr(start, (end 1) - start);
start = end 2;
}
if (start < Name.size())
Identity = Name.substr(start);
