我目前正在使用以下代码在我的程序中右修剪所有std::字符串:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);
它工作得很好,但我想知道是否有一些最终情况下它可能会失败?
当然,有优雅的选择和左修剪解决方案的答案是受欢迎的。
我目前正在使用以下代码在我的程序中右修剪所有std::字符串:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);
它工作得很好,但我想知道是否有一些最终情况下它可能会失败?
当然,有优雅的选择和左修剪解决方案的答案是受欢迎的。
当前回答
一种优雅的方法可以是
std::string & trim(std::string & str)
{
return ltrim(rtrim(str));
}
支持功能实现为:
std::string & ltrim(std::string & str)
{
auto it = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( str.begin() , it);
return str;
}
std::string & rtrim(std::string & str)
{
auto it = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( it.base() , str.end() );
return str;
}
一旦你把这些都准备好了,你也可以这样写:
std::string trim_copy(std::string const & str)
{
auto s = str;
return ltrim(rtrim(s));
}
其他回答
在空字符串的情况下,你的代码假设将1添加到string::npos得到0。String::npos的类型是String::size_type,无符号。因此,您依赖于加法的溢出行为。
有点晚了,不过没关系。c++ 11在这里,我们有lambda和auto变量。所以我的版本,也处理全空白和空字符串,是:
#include <cctype>
#include <string>
#include <algorithm>
inline std::string trim(const std::string &s)
{
auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base();
return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback));
}
我们可以从wsfront创建一个反向迭代器,并在第二个find_if_not中使用它作为终止条件,但这只在全空白字符串的情况下有用,gcc 4.8至少不足以用auto推断反向迭代器(std::string::const_reverse_iterator)的类型。我不知道构造反向迭代器有多贵,这里是YMMV。修改后,代码如下所示:
inline std::string trim(const std::string &s)
{
auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
return std::string(wsfront,std::find_if_not(s.rbegin(),std::string::const_reverse_iterator(wsfront),[](int c){return std::isspace(c);}).base());
}
上面的方法很棒,但有时您想要使用函数组合来处理例程认为是空白的部分。在这种情况下,使用函子组合操作可能会变得混乱,所以我更喜欢一个简单的循环,我可以修改修剪。这里是一个稍微修改的修剪函数,从C版本复制到这里的SO。在这个例子中,我正在修剪非字母数字字符。
string trim(char const *str)
{
// Trim leading non-letters
while(!isalnum(*str)) str++;
// Trim trailing non-letters
end = str + strlen(str) - 1;
while(end > str && !isalnum(*end)) end--;
return string(str, end+1);
}
这个……怎么样?
#include <iostream>
#include <string>
#include <regex>
std::string ltrim( std::string str ) {
return std::regex_replace( str, std::regex("^\\s+"), std::string("") );
}
std::string rtrim( std::string str ) {
return std::regex_replace( str, std::regex("\\s+$"), std::string("") );
}
std::string trim( std::string str ) {
return ltrim( rtrim( str ) );
}
int main() {
std::string str = " \t this is a test string \n ";
std::cout << "-" << trim( str ) << "-\n";
return 0;
}
注意:我对c++还是个新手,所以如果我在这里离题了,请原谅。
看来我真的是姗姗来迟了——我不敢相信7年前有人问我这个问题!
以下是我对这个问题的看法。我正在做一个项目,现在不想麻烦地使用Boost。
std::string trim(std::string str) {
if(str.length() == 0) return str;
int beg = 0, end = str.length() - 1;
while (str[beg] == ' ') {
beg++;
}
while (str[end] == ' ') {
end--;
}
return str.substr(beg, end - beg + 1);
}
这个解决方案将从左边和右边修剪。