Reputation: 183
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?
Upvotes: 1
Views: 376
Reputation: 595742
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);
Upvotes: 1
Reputation: 1974
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()
Upvotes: 1
Reputation: 25516
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.
Upvotes: 1
Reputation: 238311
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;
Upvotes: 5