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
Get Current Time in Milliseconds, or Hh:Mm:Ss:Mmm Format
How to Remove an Arbitrary Element from a Standard Heap in C++
While Writting Unittests for a Function, Should I Mock the Internal Function Calls Made
C++11 Std::To_String(Double) - No Trailing Zeros
Iterator Invalidation Rules For C++ Containers
Segmentation Fault on Large Array Sizes
Why Do We Need Virtual Functions in C++
Single Quotes Vs. Double Quotes in C or C++
In What Cases Do I Use Malloc And/Or New
How to Convert Between Big-Endian and Little-Endian Values in C++
Finding Current Executable'S Path Without /Proc/Self/Exe
Reflection and Refraction Impossible Without Recursive Ray Tracing
Using Base Pointer Register in C++ Inline Asm
Non-Const Reference Bound to Temporary, Visual Studio Bug
Explicit Template Instantiation - When Is It Used
How Does Dereferencing of a Function Pointer Happen
How to Properly Clean Up Elements from Vectors of Object Pointers