Home > Software design >  Return empty char
Return empty char

Time:01-19

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

Online Demo

  •  Tags:  
  • Related