leerzeichen entfernen
-
@Werner: Das geht aber noch deutlich schneller, indem du per find_if() das erste/letzte Nicht-Whitespace suchst und dann den Bereich dazwischen per substr() ausschneidest.
(gerade Löschen am Stringanfang ist eher langsam)
-
sicher? speicher allozieren kostet bestimmt mehr als die array elemente zu verschieben. aber vielleicht sollte man es so proggen das nur 1 mal erase für jede seite aufgerufen wird.
-
achso er legt ja eh eine kopie an
-
Bei ganz langen Strings könnte es sich lohnen, anstatt find_if, find_first_not_of und find_last_not_of zu benutzen.
-
cul schrieb:
sicher? speicher allozieren kostet bestimmt mehr als die array elemente zu verschieben.
Ja, sicher. Schließlich verschiebt jedes erase() die Elemente wieder neu (und dieses mehrfache Verschieben kostet).
aber vielleicht sollte man es so proggen das nur 1 mal erase für jede seite aufgerufen wird.
Oder so.
Edit:
Konstruktör schrieb:
Bei ganz langen Strings könnte es sich lohnen, anstatt find_if, find_first_not_of und find_last_not_of zu benutzen.
Durchaus möglich - aber dazu müsstest du erstmal einen Teststring zusammenbauen mit allen Whitespaces (in der Hinsicht sind die Algorithmen vielseitiger).
(btw kann man find_if auch mit reverse-Iteratoren verwenden ;))
-
CStoll schrieb:
Konstruktör schrieb:
Bei ganz langen Strings könnte es sich lohnen, anstatt find_if, find_first_not_of und find_last_not_of zu benutzen.
Durchaus möglich - aber dazu müsstest du erstmal einen Teststring zusammenbauen mit allen Whitespaces
Wieso das? 'find_first/last_not_of' funktioniert wunderbar.
std::string trim(std::string str) { std::string::size_type i; if ((i = str.find_first_not_of(" \t")) != std::string::npos) str.erase(0, i); else return ""; if ((i = str.find_last_not_of(" \t")) != std::string::npos) str.erase(i + 1); return str; }/EDIT: Das 'else' sollte man sich eher sparen. Das macht das ganze nicht wirklich schneller und verhindert RVO.
-
Und was ist mit \n etc?
MSDN schrieb:
isspace returns a non-zero value if c is a white-space character (0x09 – 0x0D or 0x20).
-
CStoll schrieb:
Und was ist mit \n etc?
Hm. Ich finde eigentlich nicht, dass diese durch 'trim' entfernt werden sollen aber ich bin da zugegebenermaßen durch VB vorbelastet.
Wenn man äquivalent zu 'isspace' agieren möchte sollte man das auch benutzen, sprich über 'find_if' gehen.
-
Ok, ich habe nen Gehirnstau. Kann man es weniger umständlich implementieren als folgendermaßen?
struct myspace : public std::unary_function<char, bool> { bool operator ()(char c) const { return std::isspace(c); } }; std::string trim(std::string str) { typedef std::string::iterator SI; typedef std::string::reverse_iterator CSI; SI i = std::find_if(str.begin(), str.end(), std::not1(myspace())); str.erase(str.begin(), i); CSI j = std::find_if(str.rbegin(), str.rend(), std::not1(myspace())); str.erase(j.base(), str.end()); return str; }Irgendwie stört mich die Adapter-struct aber ohne bekomme ich es nicht hin. Gut, der Typ, der die Vorlesung hält, stört meine Konzentration ein wenig.

-
Um Funktionszeiger zu wrappen, gibt es ptr_fun.
-
#include <iostream> #include <cctype> #include <string> template<typename TPredicate, typename TContainer> TContainer trimWhere(const TContainer &container, const TPredicate &condition) { TContainer result; size_t offsetFront = 0, offsetBack = 0; for(typename TContainer::const_iterator current = container.begin(); current != container.end() && condition(*current); ++current, ++offsetFront); for(typename TContainer::const_reverse_iterator current = container.rbegin(); current != container.rend() && condition(*current); ++current, ++offsetBack); result.assign(container.begin() + offsetFront, container.end() - offsetBack); return result; } inline std::string trim(const std::string &s) { return trimWhere<int(*)(int)>(s, std::isspace); } int main() { std::string test = " \r hallo \t welt \n "; std::cout << ">" << trim(test) << "<" << std::endl; }
-
schorsch code schrieb:
... return trimWhere<int(*)(int)>(s, std::isspace); ...Warum ist der Predicatetype int(*)(int) ?
Im Std steht isspace alstemplate <typename charT> bool (*)(charT, const locale&)
Gruß,
Simon2.
-
der einfachheit halber ist es ohne locale. weiß nicht, ob die c-version im standard steht, aber sowohl VC8 als auch g++ 3.4.5 sind damit einverstanden.
-
Das kommt darauf an, was du einbindest - die <cctype> verpackt afaik alle Funktionen der <ctype.h> in std::
-
Eine andere Version aus diesem Forum:
HumeSikkins schrieb:
void trimA(std::string& s) { typedef int (*Sig)(int); s.erase(s.begin(), std::find_if(s.begin(), s.end(), not1(ptr_fun(static_cast<Sig>(isspace))))); s.erase(std::find_if(s.rbegin(), s.rend(), not1(ptr_fun(static_cast<Sig>(isspace)))).base(), s.end()); }Das ist aber unter Umständen nicht ganz korrekt (siehe char vs. unsigned cahr vs. int Problematik).
Besser also:struct IsSpace : std::unary_function<char, bool> { bool operator()(char c) const { return isspace(static_cast<unsigned char>(c)) != 0; } }; void trim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), not1(IsSpace()))); s.erase(std::find_if(s.rbegin(), s.rend(), not1(IsSpace())).base(), s.end()); }Grüße,
don_basto.