How to Trim a Std::String

Trim whitespace from a String

Your code is fine. What you are seeing is a linker issue.

If you put your code in a single file like this:

#include <iostream>
#include <string>

using namespace std;

string trim(const string& str)
{
size_t first = str.find_first_not_of(' ');
if (string::npos == first)
{
return str;
}
size_t last = str.find_last_not_of(' ');
return str.substr(first, (last - first + 1));
}

int main() {
string s = "abc ";
cout << trim(s);

}

then do g++ test.cc and run a.out, you will see it works.

You should check if the file that contains the trim function is included in the link stage of your compilation process.

trim for both std::string and std::wstring [duplicate]

TCHAR is the template argument, not a preprocessor token. Use if constexpr instead.

template<typename TCHAR>
std::basic_string<TCHAR> trim(const std::basic_string<TCHAR>& s)
{
int ibegin;
if constexpr(sizeof(TCHAR) == 1) {
ibegin = s.find_first_not_of(" \t\r\n");
}
else {
ibegin = s.find_first_not_of(L" \t\r\n");
}
...
}

Removing leading and trailing spaces from a string

This is called trimming. If you can use Boost, I'd recommend it.

Otherwise, use find_first_not_of to get the index of the first non-whitespace character, then find_last_not_of to get the index from the end that isn't whitespace. With these, use substr to get the sub-string with no surrounding whitespace.

In response to your edit, I don't know the term but I'd guess something along the lines of "reduce", so that's what I called it. :) (Note, I've changed the white-space to be a parameter, for flexibility)

#include <iostream>
#include <string>

std::string trim(const std::string& str,
const std::string& whitespace = " \t")
{
const auto strBegin = str.find_first_not_of(whitespace);
if (strBegin == std::string::npos)
return ""; // no content

const auto strEnd = str.find_last_not_of(whitespace);
const auto strRange = strEnd - strBegin + 1;

return str.substr(strBegin, strRange);
}

std::string reduce(const std::string& str,
const std::string& fill = " ",
const std::string& whitespace = " \t")
{
// trim first
auto result = trim(str, whitespace);

// replace sub ranges
auto beginSpace = result.find_first_of(whitespace);
while (beginSpace != std::string::npos)
{
const auto endSpace = result.find_first_not_of(whitespace, beginSpace);
const auto range = endSpace - beginSpace;

result.replace(beginSpace, range, fill);

const auto newStart = beginSpace + fill.length();
beginSpace = result.find_first_of(whitespace, newStart);
}

return result;
}

int main(void)
{
const std::string foo = " too much\t \tspace\t\t\t ";
const std::string bar = "one\ntwo";

std::cout << "[" << trim(foo) << "]" << std::endl;
std::cout << "[" << reduce(foo) << "]" << std::endl;
std::cout << "[" << reduce(foo, "-") << "]" << std::endl;

std::cout << "[" << trim(bar) << "]" << std::endl;
}

Result:

[too much               space]  
[too much space]
[too-much-space]
[one
two]

Can trim of a string be done inplace with C++20 ranges?

Perhaps something like this?

void trim(std::string& s) {
auto not_space = [](unsigned char c){ return !std::isspace(c); };

// erase the the spaces at the back first
// so we don't have to do extra work
s.erase(
std::ranges::find_if(s | std::views::reverse, not_space).base(),
s.end());

// erase the spaces at the front
s.erase(
s.begin(),
std::ranges::find_if(s, not_space));
}

trim matching characters from start or end of string c++

std::string& trim( std::string& s, char c, bool reverse = false )
{
return reverse
? s.erase( s.find_last_not_of( c ) + 1 )
: s.erase( 0, s.find_first_not_of( c ) );
}

What's the generic & efficient trimming algorithm for Qt & std::string?

One simplistic way:

template<typename T>
T& Trim (T& value)
{
auto pos = value.size();
while(pos != 0 and value[--pos] == ' ');
if(++pos < value.size())
value.erase(pos);

if(value.size() > 0)
{
pos = -1;
while(value[++pos] == ' ');
if(pos > 0)
value.erase(0, pos);
}
return value;
}

Above will support all the types which have following methods like std::string:

  • size()
  • operator[] const
  • erase(pos, n)

Qt just lacks the erase() (name is remove()) unfortunately. To support the Qt types QString and QByteArray, we can have following wrapper:

template<class String>
struct QtWrap
{
String& m_Value;

auto size () const { return m_Value.size(); }
auto erase (int pos) { return m_Value.truncate(pos); }
auto erase (int pos, int length) { return m_Value.remove(pos, length); }
auto& operator[] (const int pos) const { return m_Value.data()[pos]; }
};

Usage:

QByteArray s;
QtWrap<QByteArray> qs{s};
Trim(qs); // Tested OK in QtCreator: Modifies the underlying `s`

Trimming C++ string in constant time

@SamVarshavchik is being coy in the comments, but it's worth spelling out: in many implementations, including libstdc++, std::string::resize() will reduce the size of a string in constant time, by reducing the length of the string and not reallocating/copying the data:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/basic_string.tcc . The estimate of O(n) is if you increase the size, forcing the string to be reallocated and copied over.

Alternatively, in C++17, std::string_view is rough immutable counterpart to "trimming" a C string by slapping a null byte. It takes a slice of a string (pointer + size) without copying its content, and you can then pass it around to various STL functions or print it from a stream.

std::string hello_world = "hello world";
auto hello = std::string_view(hello_world.data(), 5);
std::cout << hello; // prints hello

The caveat is that the string_view doesn't own the data, so you can't use it once the original string goes out of scope, and you don't want to modify the original string in a way that might cause it to reallocate.



Related Topics



Leave a reply



Submit