如何截取一个std::string?

1001
我目前在我的程序中使用以下代码来去除所有的std::string的右空格:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);

它运行良好,但我想知道是否存在一些极端情况会导致它失败?
当然,欢迎提供优雅的替代方案和左修剪解决方案。
52个回答

15
s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   

6
如果您先从右侧开始裁剪,再通过从左侧开始裁剪来引发移位,效率会稍微高一些。请注意,不要改变原有的意思。 - Galik

15
str.erase(0, str.find_first_not_of("\t\n\v\f\r ")); // left trim
str.erase(str.find_last_not_of("\t\n\v\f\r ") + 1); // right trim

在线尝试!


14
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;
}

这也适用于空值的情况。:-)

6
这只是“rtrim”,不是“ltrim”。 - SameOldNick
3
你介意使用 find_first_not_of 吗?相对容易修改。 - Abhinav Gauniyal

11

我的解决方案基于@Bill the Lizard的答案

请注意,如果输入字符串只包含空格,则这些函数将返回空字符串。

const std::string StringUtils::WHITESPACE = " \n\r\t";

std::string StringUtils::Trim(const std::string& s)
{
    return TrimRight(TrimLeft(s));
}

std::string StringUtils::TrimLeft(const std::string& s)
{
    size_t startpos = s.find_first_not_of(StringUtils::WHITESPACE);
    return (startpos == std::string::npos) ? "" : s.substr(startpos);
}

std::string StringUtils::TrimRight(const std::string& s)
{
    size_t endpos = s.find_last_not_of(StringUtils::WHITESPACE);
    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
}

10

随着C++11的推出,还引入了一个正则表达式模块,当然可以用于去除前导或尾随空格。

也许可以像这样写:

std::string ltrim(const std::string& s)
{
    static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended};
    return std::regex_replace(s, lws, "");
}

std::string rtrim(const std::string& s)
{
    static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended};
    return std::regex_replace(s, tws, "");
}

std::string trim(const std::string& s)
{
    return ltrim(rtrim(s));
}

10

这里有一个使用正则表达式进行修剪的解决方案

#include <string>
#include <regex>

string trim(string str){
    return regex_replace(str, regex("(^[ ]+)|([ ]+$)"),"");
}

我认为我会使用这个解决方案,因为它只有一行代码。我建议在正则表达式中也包括 '\n',因为它被视为空格:"(^[ \n]+)|([ \n]+$)" - Shafa95
谢谢您的评论。我同意您的观点。 - Sadidul Islam

9
我的回答是这篇文章中最佳答案的改进版,它可以去除控制字符和空格(0-32和127在ASCII表中)。 std::isgraph确定一个字符是否具有图形表示,因此您可以使用它来修改Evan的答案,从字符串的两侧删除任何没有图形表示的字符。结果是一个更加优雅的解决方案:
#include <algorithm>
#include <functional>
#include <string>

/**
 * @brief Left Trim
 *
 * Trims whitespace from the left end of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& ltrim(std::string& s) {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(),
    std::ptr_fun<int, int>(std::isgraph)));
  return s;
}

/**
 * @brief Right Trim
 *
 * Trims whitespace from the right end of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& rtrim(std::string& s) {
  s.erase(std::find_if(s.rbegin(), s.rend(),
    std::ptr_fun<int, int>(std::isgraph)).base(), s.end());
  return s;
}

/**
 * @brief Trim
 *
 * Trims whitespace from both ends of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& trim(std::string& s) {
  return ltrim(rtrim(s));
}

注意: 如果您需要支持宽字符,您也可以使用 std::iswgraph,但您还需要编辑此代码以启用 std::wstring 操作,这是我没有测试过的内容(请参阅 std::basic_string 的参考页面以了解此选项)。


3
std::ptr_fun已被弃用。 - johnbakers

8

C++11实现的Trim:

static void trim(std::string &s) {
     s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), [](char c){ return std::isspace(c); }));
     s.erase(std::find_if_not(s.rbegin(), s.rend(), [](char c){ return std::isspace(c); }).base(), s.end());
}

8
这是我使用的方法。只需从前面删除空格,如果还有剩余,也同样从后面删除。
void trim(string& s) {
    while(s.compare(0,1," ")==0)
        s.erase(s.begin()); // remove leading whitespaces
    while(s.size()>0 && s.compare(s.size()-1,1," ")==0)
        s.erase(s.end()-1); // remove trailing whitespaces
}

8
一种优雅的方法可以是这样:

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));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接