Click here to Skip to main content
15,887,477 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to remove all spaces from a string, therefore I wrote a small helper function to do it.

When tested in a basic program, everything works fine. In my more complex project it malfunctions. Furthermore, when I type std::re autocomplete offers proper replace but as soon as I type ( the signature turns into int replace( const char* _Filename ).

I have tried rewriting helper function according to this question[^] but nothing changes:

C++
// helper method for removing spaces
const char* removeSpace( std::string &str )
{
    str.erase( std::remove( str.begin(), str.end(), ' ' ), str.end() );

    return str.c_str();
}


Can you please help me to fix this problem?

Here is the content of a test .cpp file:

C++
#include <iostream>
#include <algorithm>
#include <string>
#include <fstream>

// helper method for removing spaces
const char* removeSpace( std::string &str )
{
    std::remove( str.begin(), str.end(), ' ' );
    return str.c_str();
}

int main()
{
    std::string str = " jkl ll ";

    std::cout << removeSpace( str ) << std::endl;

    return 0;
}


I am posting the content of the .cpp and .h files from the main project:

.h

C++
#ifndef _Person_h_
#define _Person_h_

#include <iostream>       
#include <list>           // std::list
#include <fstream>        // std::ifstream, std::ofstream
#include <string>         // std::string
#include <algorithm>      // std::remove, std::remove_if

class Lista
{
private:
    struct Person
    {
        // data 
       std::string dateOfBirth;

       // constructor
       Person( const char *date )
       {
           dateOfBirth = date;
       }

       // destructor
       ~Person()
       {
           dateOfBirth.clear();
       }
    };

    // linked list of Person. Person is populated with data from delimited file
    std::list<Person> persons;

public:

    // helper method for removing spaces
    const char* removeSpace( std::string &str )
    {
        std::remove( str.begin(), str.end(), ' ' );

        return str.c_str();
    }

    // method for inserting data from a file
    Lista& insertPerson( const char *inputFile, 
        const int maxTextLength = 100, 
        const char delimiter = ',' )
    {
        // open file
        std::ifstream g;
        g.open(inputFile);

        if( g.is_open() )
        {
            while( !g.eof() )
            {
                // temporary string

                std::string date;

                // get data from file
                g.getline( &date[0], maxTextLength, delimiter );

                // initialize temporary structure with data from file
                Person p( removeSpace( date ) );

                // insert it into linked list
                persons.push_back(p);

                //cleanup
                date.clear();
             }
             g.close();
         }
         return *this;
     }

     // other stuff
};

#endif


.cpp

C++
#include "Person.h"

int main()
{
    Lista p;
 
    p.insertPerson( "pipe.txt", 100, '|' );

    std::cout << p << std::endl;

    return 0;
}
Posted
Updated 23-May-14 13:19pm
v3
Comments
[no name] 23-May-14 21:24pm    
output with std::remove( str.begin(), str.end(), ' ' ); = "jklllll"
output I get with str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); = "jklll"
Visual Studio 2010
Sergey Alexandrovich Kryukov 26-May-14 1:26am    
This is a correct answer (if you remove the text after ';'). I just did not pay attention for it because, when this comment appeared, I was editing this answer in response to an OP's follow-up question. However, I later credited it in Solution 1.
—SA
[no name] 23-May-14 21:53pm    
The only way I could get your removeSpace to work in person.h was to assign &date[0] to a temp string and pass that to removeSpace.

1 solution

You should properly use the return from the function remove function. It returns an iterator to the element that follows the last element not removed:
http://www.cplusplus.com/reference/algorithm/remove[^].

Then you need to use the iterator obtained and the str.end() iterator of the original string to pass it to str.erase. So, your code will be fixed is your replace your like using remove and erase with the following line:
C++
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());

This is the use of the known erase-remove idiom explained here: http://en.wikipedia.org/wiki/Erase-remove_idiom[^].

See also: http://en.cppreference.com/w/cpp/algorithm/remove[^].

However, this is not all. Your problem with the bigger picture — design of your code — is this: with your approach, you would be jumping from std::string to the null-terminated representation of strings and back, which is utterly inefficient. The null-terminated strings adds CPU usage due to the fact that this presentation "forgets" the length of the string, so the code will have to find it by the terminator over and over each time you use it (for example, initialize another std::string with it. This adds a redundant operation of the time complexity of O(N). Once you got an std::string, you should better stay with it. Your function will be more useful if you change its signature in this way:
C++
std::string RemoveSpace(std::string &str) 
// or, optionally, return const std::string
{
    str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
    return str;
}

See also:
http://en.wikipedia.org/wiki/Time_complexity[^],
http://en.wikipedia.org/wiki/Big_O_notation[^],
http://en.wikipedia.org/wiki/Computational_complexity_theory[^].

[EDIT]

The first comment to the question by Wes Aday actually presented a correct answer (if you remove the text after ';'). I just did not pay attention for it because, when this comment appeared, I was editing this answer in response to an OP's follow-up question

—SA
 
Share this answer
 
v5
Comments
AlwaysLearningNewStuff 24-May-14 5:59am    
After I initialize strings like this : std::string date( maxTextLength, 0 ); instead of this : std::string date; everything works fine... I have also used the modified function from my post ( with erase + remove idiom applied ).
AlwaysLearningNewStuff 24-May-14 10:50am    
I have used stringstream to fix the problem.

Now there is no more need to initialize the string with maxTextLength and everything works fine. Code is much shorter, easier to maintain and more readable.

If you edit your solution with this info and offer a small example I will officially accept the solution, and upvote it as always :)

Best regards!
Sergey Alexandrovich Kryukov 24-May-14 22:10pm    
I know: you are always learning new stuff the way which can stimulate some of the readers learning with your. Even some of your mistakes cab be instructional. I appreciate that.

There is no need to add your info on different initialization of the string, because you already done it, and because it is actually irrelevant to the erase-remove problem. Your code cold be fixed by adding just a few characters in your line. So, instead, I fully reformulated my answer which was actually inaccurate. Please see the fixed and upgraded one. :-)

—SA
AlwaysLearningNewStuff 25-May-14 9:10am    
This is so educational and useful! 5ed! Thank you!
Sergey Alexandrovich Kryukov 25-May-14 10:44am    
My pleasure.
Good luck, call again.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900