zoulzubazz
zoulzubazz

Reputation: 183

Return empty char

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

Answers (4)

Remy Lebeau
Remy Lebeau

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

Online Demo

Upvotes: 1

Sebastian
Sebastian

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

Aconcagua
Aconcagua

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

eerorika
eerorika

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

Related Questions