我目前正在使用以下代码在我的程序中右修剪所有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);
它工作得很好,但我想知道是否有一些最终情况下它可能会失败?
当然,有优雅的选择和左修剪解决方案的答案是受欢迎的。
当前回答
在c++ 17中,你可以使用basic_string_view::remove_prefix和basic_string_view::remove_suffix:
std::string_view trim(std::string_view s)
{
s.remove_prefix(std::min(s.find_first_not_of(" \t\r\v\n"), s.size()));
s.remove_suffix(std::min(s.size() - s.find_last_not_of(" \t\r\v\n") - 1, s.size()));
return s;
}
一个不错的替代方案:
std::string_view ltrim(std::string_view s)
{
s.remove_prefix(std::distance(s.cbegin(), std::find_if(s.cbegin(), s.cend(),
[](int c) {return !std::isspace(c);})));
return s;
}
std::string_view rtrim(std::string_view s)
{
s.remove_suffix(std::distance(s.crbegin(), std::find_if(s.crbegin(), s.crend(),
[](int c) {return !std::isspace(c);})));
return s;
}
std::string_view trim(std::string_view s)
{
return ltrim(rtrim(s));
}
其他回答
有点晚了,不过没关系。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());
}
对噪音做出我的解决方案。Trim默认创建一个新字符串并返回修改后的字符串,而trim_in_place则修改传递给它的字符串。trim函数支持c++11 move语义。
#include <string>
// modifies input string, returns input
std::string& trim_left_in_place(std::string& str) {
size_t i = 0;
while(i < str.size() && isspace(str[i])) { ++i; };
return str.erase(0, i);
}
std::string& trim_right_in_place(std::string& str) {
size_t i = str.size();
while(i > 0 && isspace(str[i - 1])) { --i; };
return str.erase(i, str.size());
}
std::string& trim_in_place(std::string& str) {
return trim_left_in_place(trim_right_in_place(str));
}
// returns newly created strings
std::string trim_right(std::string str) {
return trim_right_in_place(str);
}
std::string trim_left(std::string str) {
return trim_left_in_place(str);
}
std::string trim(std::string str) {
return trim_left_in_place(trim_right_in_place(str));
}
#include <cassert>
int main() {
std::string s1(" \t\r\n ");
std::string s2(" \r\nc");
std::string s3("c \t");
std::string s4(" \rc ");
assert(trim(s1) == "");
assert(trim(s2) == "c");
assert(trim(s3) == "c");
assert(trim(s4) == "c");
assert(s1 == " \t\r\n ");
assert(s2 == " \r\nc");
assert(s3 == "c \t");
assert(s4 == " \rc ");
assert(trim_in_place(s1) == "");
assert(trim_in_place(s2) == "c");
assert(trim_in_place(s3) == "c");
assert(trim_in_place(s4) == "c");
assert(s1 == "");
assert(s2 == "c");
assert(s3 == "c");
assert(s4 == "c");
}
从Cplusplus.com上窃取的
std::string choppa(const std::string &t, const std::string &ws)
{
std::string str = t;
size_t found;
found = str.find_last_not_of(ws);
if (found != std::string::npos)
str.erase(found+1);
else
str.clear(); // str is all whitespace
return str;
}
这也适用于空情况。: -)
std::string trim( std::string && str )
{
size_t end = str.find_last_not_of( " \n\r\t" );
if ( end != std::string::npos )
str.resize( end + 1 );
size_t start = str.find_first_not_of( " \n\r\t" );
if ( start != std::string::npos )
str = str.substr( start );
return std::move( str );
}
我喜欢tzaman的解决方案,唯一的问题是它不修剪只包含空格的字符串。
为了纠正这1个缺陷,在2个微调行之间添加str.clear()
std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;