views:

1782

answers:

9

Whats the most efficient way of removing a 'newline' from a std::string?

A: 

If its anywhere in the string than you can't do better than O(n).

And the only way is to search for '\n' in the string and erase it.

for(int i=0;i<s.length();i++) if(s[i]=='\n') s.erase(s.begin()+i);

For more newlines than:

int n=0;
for(int i=0;i<s.length();i++){
    if(s[i]=='\n'){
        n++;//we increase the number of newlines we have found so far
    }else{
        s[i-n]=s[i];
    }
}
s.resize(s.length()-n);//to delete only once the last n elements witch are now newlines

It erases all the newlines once.

csiz
This implementation will not handle consecutive newlines properly, since `i` is incremented regardless of whether an element is erased.
Greg Hewgill
i just noticed, I'll edit this
csiz
+1  A: 

If the newline is expected to be at the end of the string, then:

if (!s.empty() && s[s.length()-1] == '\n') {
    s.erase(s.length()-1);
}

If the string can contain many newlines anywhere in the string:

std::string::size_type i = 0;
while (i < s.length()) {
    i = s.find('\n', i);
    if (i == std::string:npos) {
        break;
    }
    s.erase(i);
}
Greg Hewgill
First version perfect. Second version would be easier to use std::erase(std::removr(XXX))
Martin York
I've never been terribly comfortable with the semantics of remove() and always have to look it up because it's not obvious. My above implementation is simple and direct, but not the most efficient. If efficiency is important, a slightly different solution is needed.
Greg Hewgill
the question was, "what's the most efficient way...", so I guess efficiency is important ;)
Pieter
+3  A: 

You should use the erase-remove idiom, looking for '\n'. This will work for any standard sequence container; not just string.

coppro
A: 

Use std::algorithms. This question has some suitably reusable suggestions Remove spaces from std::string in C++

Stuart
A: 
s.erase(std::remove(s.begin(), s.end(), '\n'), s.end());
hrnt
A: 

The code removes all newlines from the string str.

O(N) implementation best served without comments on SO and with comments in production.

unsigned shift=0;
for (unsigned i=0; i<length(str); ++i){
    if (str[i] == '\n') {
        ++shift;
    }else{
        str[i-shift] = str[i];
    }
}
str.resize(str.length() - shift);
Pavel Shved
+9  A: 
#include <algorithm>
#include <string>

std::string str;

str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());

The behavior of std::remove may not quite be what you'd expect. See an explanation of it here.

luke
If there's any chance of newlines from other platforms, maybe delete '\r' characters too. A second call to erase and std::remove etc is no big deal performance-wise. Alternatives, such as using std::remove_if with a predicate function, will probably be slower.
Steve314
If your data was originally loaded from a file opened in text (ascii, non-binary) mode I believe it automatically converts all newline conventions to a simple '\n'. I'm looking for a definitive reference to corroborate.
luke
http://msdn.microsoft.com/en-us/library/kt0etdcs%28VS.71%29.aspx -- thats for fread(), but I believe iostream reads and writes have the same behavior.
luke
A: 
 std::string some_str = SOME_VAL;
 if ( some_str.size() > 0 && some_str[some_str.length()-1] == '\n' ) 
  some_str.resize( some_str.length()-1 );

or (removes several newlines at the end)

some_str.resize( some_str.find_last_not_of(L"\n")+1 );
Kirill V. Lyadvinsky
A: 

All these answers seem a bit heavy to me.

If you just flat out remove the '\n' and move everything else back a spot, you are liable to have some characters slammed together in a weird-looking way. So why not just do the simple (and most efficient) thing: Replace all '\n's with spaces?

for (int i = 0; i < str.length();i++) {
   if (str[i] == '\n') {
      str[i] = ' ';
   }
}

There may be ways to improve the speed of this at the edges, but it will be way quicker than moving whole chunks of the string around in memory.

T.E.D.