views:

2889

answers:

8

Can anyone suggest a way of stripping tab characters ( "\t"s ) from a string? CString or std::string.

So that "1E10      " for example becomes "1E10".

Thanks in anticipation.

+2  A: 

Scan the string and remove all the found occurences.

sharptooth
A: 

First idea would be to use remove

remove(myString.begin(), myString.end(), "\t");

Though you might have to use remove_if instead if that comparison doesn't work.

drby
remove() is half of it -- you also need to wrap that call to remove() with a call to myString.erase(), since remove() doesn't actually shorten the string (it doesn't (and can't) know how).
j_random_hacker
+1  A: 

CString replace?

replace('\t', '')

PoweRoy
Won't work. '' stands for NULL character (at least in VC++). Will cause problems.
sharptooth
I think he means "". Seems to work for me.
AndyUK
More specifically replace( "\t", "" )
AndyUK
Yeap, this will work, but it's a lot of overhead.
sharptooth
I didn't test is but I inteded to use '\t' because I think "\t" will look for the text \t instead of the tab character (don't know for sure).
PoweRoy
Nope, replace("\t", "") will work just as needed, but it's not very time-efficient. Escape sequences work the same in character literals and string literals.
sharptooth
+6  A: 

The remove algorithm shifts all characters not to be deleted to the beginning, overwriting deleted characters but it doesn't modify the container's length (since it works on iterators and doesn't know the underlying container). To achieve this, call erase:

str.erase(remove(str.begin(), str.end(), '\t'), str.end());
Konrad Rudolph
I think you have the parameters to erase() mixed up. You want to erase *from* the iterator returned by remove() to the *end* of str.
j_random_hacker
oops :) yes, of course.
Konrad Rudolph
+2 for you Konrad! :)
j_random_hacker
P.S: Actually I don't think remove() shifts the found characters to the end -- I think the end will just contain whatever it contained initially.
j_random_hacker
@j_r_h: Not, it really does. Basically, `remove(a, b, v)` is exactly equal to `stable_partition(a, b, p)` with the predicate p = `_1 != value`.
Konrad Rudolph
Are you sure? According to http://www.sgi.com/tech/stl/remove.html: "The iterators in the range [new_last, last) are all still dereferenceable, but the elements that they point to are unspecified." Certainly the MinGW and MSVC++8 implementations of remove() != stable_partition().
j_random_hacker
Also remove() is an in-place O(n) algorithm, while stable_partition() seems to be "harder" -- at least the SGI implementation of stable_partition() tries to allocate a temporary buffer and use that in O(n) time, otherwise falling back to an O(nlog n) algorithm.
j_random_hacker
`j_random_hacker`: Sorry, I can't argue from the Standard, I looked at the GCC source. Furthermore, I readily agree that a general-purpose stable sort may be more difficult to implement, however, at least the GCC `remove` implementation does exactly what I said above.
Konrad Rudolph
(cont) And due to the Standard constraints on runtime (exactly N applications I of the predicate) I fail to see any other workable implementation. But that's strictly speculation, I admit.
Konrad Rudolph
@Konrad: Sorry to go on but I have to clear this up! I just grovelled through the g++ 4.1.2 sources, and it doesn't perform the equivalent of stable_partition() either. What version do you have? (BTW, I couldn't tell if your 2nd comment was in support of your original statement or against it...)
j_random_hacker
@j_r_h: My 2nd comment was in support of the original statement. As for the source: GCC 4.2 `remove` invokes `find` and `remove_copy`. `find` gets the first occurrence and `r_c` shifts all subsequent finds to the end.
Konrad Rudolph
(cont'd) That said, I see now that you are right that they are not identical; `remove` just moves the other elements to the front, it does not move the deleted elements to the back. So yes, you were right all along. But I had to test it first: http://pastie.org/396239 So, thanks for persisting!
Konrad Rudolph
@Konrad: No problem, glad we cleared that up and I wasn't losing my mind after all! :)
j_random_hacker
+12  A: 

If you want to remove all occurences in the string, then you can use the erase/remove idiom:

#include <algorithm>

s.erase(std::remove(s.begin(), s.end(), '\t'), s.end());

If you want to remove only the tab at the beginning and end of the string, you could use the boost string algorithms:

#include <boost/algorithm/string.hpp>

boost::trim(s); // removes all leading and trailing white spaces
boost::trim_if(s, boost::is_any_of("\t")); // removes only tabs

If using Boost is too much overhead, you can roll your own trim function using find_first_not_of and find_last_not_of string methods.

std::string::size_type begin = s.find_first_not_of("\t");
std::string::size_type end   = s.find_last_not_of("\t");

std::string trimmed = s.substr(begin, end-begin + 1);
Luc Touraille
std::remove() doesn't make the string any shorter -- it just returns an iterator saying "the new string ends here." You need to call s.erase() afterwards with that iterator to actually shorten the string.
j_random_hacker
You're right, I forgot using the erase/remove idiom. Corrected.
Luc Touraille
+2 for you too Luc :)
j_random_hacker
+5  A: 

hackingwords' answer gets you halfway there. But remove() from <algorithm> doesn't actually make the string any shorter -- it just returns an iterator saying "the new sequence would end here." You need to call myString().erase() to do that:

#include <string>
#include <algorithm>    // For remove()

using namespace std;

myStr.erase(remove(myStr.begin(), myStr.end(), '\t'), myStr.end());
j_random_hacker
+2  A: 

HackingWords is nearly there: Use erase in combination with remove.

std::string my_string = "this\tis\ta\ttabbed\tstring";
my_string.erase( std::remove( my_string.begin( ), my_string.end( ), my_string.end(), '\t') );
graham.reeds
I think you made the same mistake as Konrad Rudolph -- you need to delete *from* the iterator returned by std::remove() to the *end* of the string.
j_random_hacker
+2 for the correction graham.
j_random_hacker
Yeah, racing to be first means you have to code quickly.
graham.reeds
+2  A: 

Since others already answered how to do this with std::string, here's what you can use for CString:

myString.TrimRight( '\t' ); // trims tabs from end of string
myString.Trim( '\t' ); // trims tabs from beginning and end of string

if you want to get rid of all tabs, even those inside the string, use

myString.Replace( _T("\t"), _T("") );
Stefan