I know there are several ways to do this in Java and C that are nice, but in C++ I can't seem to find a way to easily implement a string trimming function.
This is what I currently have:
string trim(string& str)
{
size_t first = str.find_first_not_of(' ');
size_t last = str.find_last_not_of(' ');
return str.substr(first, (last-first+1));
}
but whenever I try and call
trim(myString);
I get the compiler error
/tmp/ccZZKSEq.o: In function `song::Read(std::basic_ifstream<char,
std::char_traits<char> >&, std::basic_ifstream<char, std::char_traits<char> >&, char const*, char const*)':
song.cpp:(.text+0x31c): undefined reference to `song::trim(std::string&)'
collect2: error: ld returned 1 exit status
I am trying to find a simple and standard way of trimming leading and trailing whitespace from a string without it taking up 100 lines of code, and I tried using regex, but could not get that to work as well.
I also cannot use Boost.
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.
Here is how you can do it:
std::string & trim(std::string & str)
{
return ltrim(rtrim(str));
}
And the supportive functions are implemeted as:
std::string & ltrim(std::string & str)
{
auto it2 = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( str.begin() , it2);
return str;
}
std::string & rtrim(std::string & str)
{
auto it1 = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( it1.base() , str.end() );
return str;
}
And once you've all these in place, you can write this as well:
std::string trim_copy(std::string const & str)
{
auto s = str;
return ltrim(rtrim(s));
}
Try this
I think that substr() throws an exception if str only contains the whitespace.
I would modify it to the following code:
string trim(string& str)
{
size_t first = str.find_first_not_of(' ');
if (first == std::string::npos)
return "";
size_t last = str.find_last_not_of(' ');
return str.substr(first, (last-first+1));
}
#include <vector>
#include <numeric>
#include <sstream>
#include <iterator>
void Trim(std::string& inputString)
{
std::istringstream stringStream(inputString);
std::vector<std::string> tokens((std::istream_iterator<std::string>(stringStream)), std::istream_iterator<std::string>());
inputString = std::accumulate(std::next(tokens.begin()), tokens.end(),
tokens[0], // start with first element
[](std::string a, std::string b) { return a + " " + b; });
}
In addition to answer of @gjha:
inline std::string ltrim_copy(const std::string& str)
{
auto it = std::find_if(str.cbegin(), str.cend(),
[](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
return std::string(it, str.cend());
}
inline std::string rtrim_copy(const std::string& str)
{
auto it = std::find_if(str.crbegin(), str.crend(),
[](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
return it == str.crend() ? std::string() : std::string(str.cbegin(), ++it.base());
}
inline std::string trim_copy(const std::string& str)
{
auto it1 = std::find_if(str.cbegin(), str.cend(),
[](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
if (it1 == str.cend()) {
return std::string();
}
auto it2 = std::find_if(str.crbegin(), str.crend(),
[](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
return it2 == str.crend() ? std::string(it1, str.cend()) : std::string(it1, ++it2.base());
}
来源:https://stackoverflow.com/questions/25829143/trim-whitespace-from-a-string