从字符串中删除前导和尾随空格

时间:2009-11-25 16:22:37

标签: c++ string

如何在C ++中从字符串对象中删除空格。
例如,如何从下面的字符串对象中删除前导和尾随空格。

//Original string: "         This is a sample string                    "
//Desired string: "This is a sample string"

据我所知,字符串类没有提供任何删除前导和尾随空格的方法。

要添加问题,如何扩展此格式以处理字符串的单词之间的额外空格。例如,

// Original string: "          This       is         a sample   string    " 
// Desired string:  "This is a sample string"  

使用解决方案中提到的字符串方法,我可以考虑分两步完成这些操作。

  1. 删除前导和尾随空格。
  2. 在字边界重复使用 find_first_of,find_last_of,find_first_not_of,find_last_not_of和substr 以获得所需的格式。

24 个答案:

答案 0 :(得分:114)

这称为修剪。如果你可以使用Boost,我会推荐它。

否则,使用find_first_not_of获取第一个非空白字符的索引,然后使用find_last_not_of从不是空白的末尾获取索引。使用这些,使用substr来获取没有周围空格的子字符串。

为了回应你的编辑,我不知道这个术语,但我猜的是“减少”这个词,所以这就是我所说的。 :)(注意,我已将白色空间更改为参数,以获得灵活性)

#include <iostream>
#include <string>

std::string trim(const std::string& str,
                 const std::string& whitespace = " \t")
{
    const auto strBegin = str.find_first_not_of(whitespace);
    if (strBegin == std::string::npos)
        return ""; // no content

    const auto strEnd = str.find_last_not_of(whitespace);
    const auto strRange = strEnd - strBegin + 1;

    return str.substr(strBegin, strRange);
}

std::string reduce(const std::string& str,
                   const std::string& fill = " ",
                   const std::string& whitespace = " \t")
{
    // trim first
    auto result = trim(str, whitespace);

    // replace sub ranges
    auto beginSpace = result.find_first_of(whitespace);
    while (beginSpace != std::string::npos)
    {
        const auto endSpace = result.find_first_not_of(whitespace, beginSpace);
        const auto range = endSpace - beginSpace;

        result.replace(beginSpace, range, fill);

        const auto newStart = beginSpace + fill.length();
        beginSpace = result.find_first_of(whitespace, newStart);
    }

    return result;
}

int main(void)
{
    const std::string foo = "    too much\t   \tspace\t\t\t  ";
    const std::string bar = "one\ntwo";

    std::cout << "[" << trim(foo) << "]" << std::endl;
    std::cout << "[" << reduce(foo) << "]" << std::endl;
    std::cout << "[" << reduce(foo, "-") << "]" << std::endl;

    std::cout << "[" << trim(bar) << "]" << std::endl;
}

结果:

[too much               space]  
[too much space]  
[too-much-space]  
[one  
two]  

答案 1 :(得分:42)

轻松地从一行中的std :: string中删除前导,尾随和额外空格

value = std::regex_replace(value, std::regex("^ +| +$|( ) +"), "$1");

仅删除前导空格

value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to<char>(), ' ')));

value = std::regex_replace(value, std::regex("^ +"), "");

仅删除尾随空格

value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end());

value = std::regex_replace(value, std::regex(" +$"), "");

只删除多余的空格

value = regex_replace(value, std::regex(" +"), " ");

答案 2 :(得分:30)

我目前正在使用这些功能:

// trim from left
inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v")
{
    s.erase(0, s.find_first_not_of(t));
    return s;
}

// trim from right
inline std::string& rtrim(std::string& s, const char* t = " \t\n\r\f\v")
{
    s.erase(s.find_last_not_of(t) + 1);
    return s;
}

// trim from left & right
inline std::string& trim(std::string& s, const char* t = " \t\n\r\f\v")
{
    return ltrim(rtrim(s, t), t);
}

// copying versions

inline std::string ltrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return ltrim(s, t);
}

inline std::string rtrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return rtrim(s, t);
}

inline std::string trim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return trim(s, t);
}

答案 3 :(得分:19)

Boost string trim algorithm

#include <boost/algorithm/string/trim.hpp>

[...]

std::string msg = "   some text  with spaces  ";
boost::algorithm::trim(msg);

答案 4 :(得分:7)

在jon-hanson建议使用boost之后修剪前导和尾随空格的示例(仅删除尾随和待定空格):

#include <boost/algorithm/string/trim.hpp>

std::string str = "   t e s t    ";

boost::algorithm::trim ( str );

"t e s t"

中的结果

还有

  • trim_left会产生"t e s t "
  • trim_right会产生" t e s t"

答案 5 :(得分:7)

以下是如何做到这一点:

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

支持功能的实现如下:

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

一旦你完成所有这些,你也可以写下这个:

std::string trim_copy(std::string const & str)
{
   auto s = str;
   return ltrim(rtrim(s));
}

试试这个

答案 6 :(得分:7)

这是我解决前导空格和尾随空格的解决方案......

std::string stripString = "  Plamen     ";
while(!stripString.empty() && std::isspace(*stripString.begin()))
    stripString.erase(stripString.begin());

while(!stripString.empty() && std::isspace(*stripString.rbegin()))
    stripString.erase(stripString.length()-1);

结果是&#34; Plamen&#34;

答案 7 :(得分:4)

/// strip a string, remove leading and trailing spaces
void strip(const string& in, string& out)
{
    string::const_iterator b = in.begin(), e = in.end();

    // skipping leading spaces
    while (isSpace(*b)){
        ++b;
    }

    if (b != e){
        // skipping trailing spaces
        while (isSpace(*(e-1))){
            --e;
        }
    }

    out.assign(b, e);
}

在上面的代码中,isSpace()函数是一个布尔函数,它告诉一个字符是否是一个空格,你可以实现这个函数来反映你的需要,或者只是从“ctype.h”调用isspace()如果你愿意的话。

答案 8 :(得分:3)

使用标准库有许多好处,但必须注意一些导致异常的特殊情况。例如,没有一个答案涵盖了C ++字符串具有某些Unicode字符的情况。在这种情况下,如果使用函数 isspace ,则会抛出异常。

我一直在使用以下代码修剪字符串以及其他一些可能派上用场的操作。这段代码的主要好处是:它非常快(比我测试的任何代码都快),它只使用标准库,它永远不会导致异常:

#include <string>
#include <algorithm>
#include <functional>
#include <locale>
#include <iostream>

typedef unsigned char BYTE;

std::string strTrim(std::string s, char option = 0)
{
    // convert all whitespace characters to a standard space
    std::replace_if(s.begin(), s.end(), (std::function<int(BYTE)>)::isspace, ' ');

    // remove leading and trailing spaces
    size_t f = s.find_first_not_of(' ');
    if (f == std::string::npos) return "";
    s = s.substr(f, s.find_last_not_of(' ') - f + 1);

    // remove consecutive spaces
    s = std::string(s.begin(), std::unique(s.begin(), s.end(),
        [](BYTE l, BYTE r){ return l == ' ' && r == ' '; }));

    switch (option)
    {
    case 'l':  // convert to lowercase
        std::transform(s.begin(), s.end(), s.begin(), ::tolower);
        return s;
    case 'U':  // convert to uppercase
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    case 'n':  // remove all spaces
        s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
        return s;
    default: // just trim
        return s;
    }
}

答案 9 :(得分:3)

修剪前导和尾随空格的示例

std::string aString("    This is a string to be trimmed   ");
auto start = aString.find_first_not_of(' ');
auto end = aString.find_last_not_of(' ');
std::string trimmedString;
trimmedString = aString.substr(start, (end - start) + 1);

trimmedSring = aString.substr(aString.find_first_not_of(' '), (aString.find_last_not_of(' ') - aString.find_first_not_of(' ')) + 1);

答案 10 :(得分:2)

我已经测试了这一切,一切正常。所以这个方法processInput只是要求用户输入内容。它将返回一个内部没有多余空格的字符串,也不会在开头或结尾添加额外的空格。希望这可以帮助。 (还放了一堆评论,以使其易于理解)。

你可以在底部的main()中看到如何实现它

#include <string>
#include <iostream>

string processInput() {
  char inputChar[256];
  string output = "";
  int outputLength = 0;
  bool space = false;
  // user inputs a string.. well a char array
  cin.getline(inputChar,256);
  output = inputChar;
       string outputToLower = "";
  // put characters to lower and reduce spaces
  for(int i = 0; i < output.length(); i++){
    // if it's caps put it to lowercase
    output[i] = tolower(output[i]);
    // make sure we do not include tabs or line returns or weird symbol for null entry array thingy
    if (output[i] != '\t' && output[i] != '\n' && output[i] != 'Ì') {
      if (space) {
        // if the previous space was a space but this one is not, then space now is false and add char
        if (output[i] != ' ') {
          space = false;
          // add the char
          outputToLower+=output[i];
        }
      } else {
        // if space is false, make it true if the char is a space
        if (output[i] == ' ') {
          space = true;
        }
        // add the char
        outputToLower+=output[i];
      }
    }
  }
  // trim leading and tailing space
  string trimmedOutput = "";
  for(int i = 0; i < outputToLower.length(); i++){
    // if it's the last character and it's not a space, then add it
    // if it's the first character and it's not a space, then add it
    // if it's not the first or the last then add it
    if (i == outputToLower.length() - 1 && outputToLower[i] != ' ' || 
      i == 0 && outputToLower[i] != ' ' || 
      i > 0 && i < outputToLower.length() - 1) {
      trimmedOutput += outputToLower[i];
    } 
  }
  // return
  output = trimmedOutput;
  return output;
}

int main() {
  cout << "Username: ";
  string userName = processInput();
  cout << "\nModified Input = " << userName << endl;
}

答案 11 :(得分:2)

这可能是最简单的。

您可以使用string::findstring::rfind从两边查找空格并减少字符串。

void TrimWord(std::string& word)
{
    if (word.empty()) return;

    // Trim spaces from left side
    while (word.find(" ") == 0)
    {
        word.erase(0, 1);
    }

    // Trim spaces from right side
    size_t len = word.size();
    while (word.rfind(" ") == --len)
    {
        word.erase(len, len + 1);
    }
}

答案 12 :(得分:1)

C ++ 17引入了std::basic_string_view,这是一个类模板,它引用字符型对象的恒定连续序列,即字符串的视图。除了具有与std::basic_string类似的界面外,它还具有两个附加功能:remove_prefix(),通过向前移动视图来缩小视图;和 remove_suffix(),通过向后移动视图来缩小视图。这些可用于修剪前导和尾随空间:

#include <string_view>
#include <string>

std::string_view ltrim(std::string_view str)
{
    const auto pos(str.find_first_not_of(" \t"));
    str.remove_prefix(pos);
    return str;
}

std::string_view rtrim(std::string_view str)
{
    const auto pos(str.find_last_not_of(" \t"));
    str.remove_suffix(str.length() - pos - 1);
    return str;
}

std::string_view trim(std::string_view str)
{
    str = ltrim(str);
    str = rtrim(str);
    return str;
}

int main()
{
    std::string str = "   hello world   ";
    auto sv1{ ltrim(str) };  // "hello world   "
    auto sv2{ rtrim(str) };  // "   hello world"
    auto sv3{ trim(str) };   // "hello world"

    //If you want, you can create std::string objects from std::string_view objects
    auto s1{ sv1 };
    auto s2{ sv2 };
    auto s3{ sv3 };
}

注意:std::string_view是一个没有所有权的引用,因此仅在原始字符串仍然存在的情况下它才有效。

答案 13 :(得分:1)

为何复杂化?

std::string removeSpaces(std::string x){
    if(x[0] == ' '){ x.erase(0, 1); }
    if(x[x.length()-1] == ' '){ x.erase(x.length()-1, x.length()); }
    return x;
}

即使提升失败,也没有正则表达式,没有奇怪的东西,也没有库,这都有效。

答案 14 :(得分:0)

在字符串中使用 pop_back() 函数可以实现去除前后空格的恒定时间和空间复杂度。代码如下:

void trimTrailingSpaces(string& s) {
    while (s.size() > 0 && s.back() == ' ') {
        s.pop_back();
    }
}

void trimSpaces(string& s) {
    //trim trailing spaces.
    trimTrailingSpaces(s);
    //trim leading spaces
    //To reduce complexity, reversing and removing trailing spaces 
    //and again reversing back
    reverse(s.begin(), s.end());
    trimTrailingSpaces(s);
    reverse(s.begin(), s.end());
}

答案 15 :(得分:0)

string trim(const string & sStr)
{
    int nSize = sStr.size();
    int nSPos = 0, nEPos = 1, i;
    for(i = 0; i< nSize; ++i) {
        if( !isspace( sStr[i] ) ) {
            nSPos = i ;
            break;
        }
    }
    for(i = nSize -1 ; i >= 0 ; --i) {
        if( !isspace( sStr[i] ) ) {
            nEPos = i;
            break;
        }
    }
    return string(sStr, nSPos, nEPos - nSPos + 1);
}

答案 16 :(得分:0)

要解决此问题,如何扩展此格式以处理字符串单词之间的多余空格。

实际上,这比考虑多个前导和尾随空白字符要简单得多。您需要做的就是从整个字符串中删除重复的相邻空白字符。

相邻空白的谓词将简单地是:

auto by_space = [](unsigned char a, unsigned char b) {
    return std::isspace(a) and std::isspace(b);
};

然后可以使用std::unique和擦除删除习惯来消除那些重复的相邻空白字符:

// s = "       This       is       a sample   string     "  
s.erase(std::unique(std::begin(s), std::end(s), by_space), 
        std::end(s));
// s = " This is a sample string "  

这确实可能在正面和/或背面留下一个多余的空格字符。这可以很容易地删除:

if (std::size(s) && std::isspace(s.back()))
    s.pop_back();

if (std::size(s) && std::isspace(s.front()))
    s.erase(0, 1);

这里是demo

答案 17 :(得分:0)

没有--user,没有boost,只有regex库。就这么简单。

string

答案 18 :(得分:0)

  

干净整洁

 void trimLeftTrailingSpaces(string &input) {
        input.erase(input.begin(), find_if(input.begin(), input.end(), [](int ch) {
            return !isspace(ch);
        }));
    }

    void trimRightTrailingSpaces(string &input) {
        input.erase(find_if(input.rbegin(), input.rend(), [](int ch) {
            return !isspace(ch);
        }).base(), input.end());
    }

答案 19 :(得分:0)

    char *str = (char*) malloc(50 * sizeof(char));
    strcpy(str, "    some random string (<50 chars)  ");

    while(*str == ' ' || *str == '\t' || *str == '\n')
            str++;

    int len = strlen(str);

    while(len >= 0 && 
            (str[len - 1] == ' ' || str[len - 1] == '\t' || *str == '\n')
    {
            *(str + len - 1) = '\0';
            len--;
    }

    printf(":%s:\n", str);

答案 20 :(得分:0)

对于行距和尾随空格,如何:

string string_trim(const string& in) {

    stringstream ss;
    string out;
    ss << in;
    ss >> out;
    return out;

}

或者是一句话:

string trim_words(const string& sentence) {
    stringstream ss;
    ss << sentence;
    string s;
    string out;

    while(ss >> s) {

        out+=(s+' ');
    }
    return out.substr(0, out.length()-1);
}

答案 21 :(得分:0)

void removeSpaces(string& str)
{
    /* remove multiple spaces */
    int k=0;
    for (int j=0; j<str.size(); ++j)
    {
            if ( (str[j] != ' ') || (str[j] == ' ' && str[j+1] != ' ' ))
            {
                    str [k] = str [j];
                    ++k;
            }

    }
    str.resize(k);

    /* remove space at the end */   
    if (str [k-1] == ' ')
            str.erase(str.end()-1);
    /* remove space at the begin */
    if (str [0] == ' ')
            str.erase(str.begin());
}

答案 22 :(得分:-1)

erase-remove idiom怎么样?

std::string s("...");
s.erase( std::remove(s.begin(), s.end(), ' '), s.end() );

对不起。我太迟见了,你不想删除所有空格。

答案 23 :(得分:-1)

我的解决方案不使用任何STL方法但只使用C ++字符串自己的方法,如下所示:

void processString(string &s) {
    if ( s.empty() ) return;

    //delete leading and trailing spaces of the input string
    int notSpaceStartPos = 0, notSpaceEndPos = s.length() - 1;
    while ( s[notSpaceStartPos] == ' ' ) ++notSpaceStartPos;
    while ( s[notSpaceEndPos] == ' ' ) --notSpaceEndPos;
    if ( notSpaceStartPos > notSpaceEndPos ) { s = ""; return; }
    s = s.substr(notSpaceStartPos, notSpaceEndPos - notSpaceStartPos + 1);

    //reduce multiple spaces between two words to a single space 
    string temp;
    for ( int i = 0; i < s.length(); i++ ) {
        if ( i > 0 && s[i] == ' ' && s[i-1] == ' ' ) continue;
        temp.push_back(s[i]);
    }
    s = temp;
}

我使用此方法传递LeetCode问题Reverse Words in a String