我目前正在使用以下代码在我的程序中右修剪所有std::字符串:

std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);

它工作得很好,但我想知道是否有一些最终情况下它可能会失败?

当然,有优雅的选择和左修剪解决方案的答案是受欢迎的。


当前回答

你所做的是好的,是稳健的。我用同样的方法已经很长时间了,我还没有找到一个更快的方法:

const char* ws = " \t\n\r\f\v";

// trim from end of string (right)
inline std::string& rtrim(std::string& s, const char* t = ws)
{
    s.erase(s.find_last_not_of(t) + 1);
    return s;
}

// trim from beginning of string (left)
inline std::string& ltrim(std::string& s, const char* t = ws)
{
    s.erase(0, s.find_first_not_of(t));
    return s;
}

// trim from both ends of string (right then left)
inline std::string& trim(std::string& s, const char* t = ws)
{
    return ltrim(rtrim(s, t), t);
}

通过提供要修剪的字符,您可以灵活地修剪非空白字符,并高效地只修剪您想修剪的字符。

其他回答

对噪音做出我的解决方案。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");  
}

这个好吗?(因为这篇文章完全需要另一个答案:)

string trimBegin(string str)
{
    string whites = "\t\r\n ";
    int i = 0;
    while (whites.find(str[i++]) != whites::npos);
    str.erase(0, i);
    return str;
}

类似的情况下,trimEnd,只是反转极化,指数。

我喜欢tzaman的解决方案,唯一的问题是它不修剪只包含空格的字符串。

为了纠正这1个缺陷,在2个微调行之间添加str.clear()

std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;

还有一种选择-从两端删除一个或多个字符。

string strip(const string& s, const string& chars=" ") {
    size_t begin = 0;
    size_t end = s.size()-1;
    for(; begin < s.size(); begin++)
        if(chars.find_first_of(s[begin]) == string::npos)
            break;
    for(; end > begin; end--)
        if(chars.find_first_of(s[end]) == string::npos)
            break;
    return s.substr(begin, end-begin+1);
}

使用Boost的字符串算法是最简单的:

#include <boost/algorithm/string.hpp>

std::string str("hello world! ");
boost::trim_right(str);

STR现在是"hello world!"。还有trim_left和trim,它们修剪两边。


如果你给上面的函数名加上_copy后缀,例如trim_copy,函数将返回一个经过修剪的字符串副本,而不是通过引用修改它。

如果你给上面的任何函数名加上_if后缀,例如trim_copy_if,你可以修剪所有满足自定义谓词的字符,而不是只有空白。