【问题标题】:Trim / Remove useless whitespace and tab from a string修剪/删除字符串中无用的空格和制表符
【发布时间】:2015-02-17 12:37:18
【问题描述】:

谁能建议一种从字符串中去除制表符 ("\t"s) 的方法? (std::string)

我知道我可以做很多事情:

str.erase (std::remove (str.begin(), str.end(), ' '), str.end());

但它会去掉所有的空格。

例如我想要这个:

push int32(45)__WT__ push int32(45) __WT__

变成这样:

push int32(45)

关键字之间只有一个空格的字符串。

  • __WT__ = 无用的空格或制表符。

感谢期待。

【问题讨论】:

    标签: c++ string trim c++98


    【解决方案1】:

    我只能使用 C++98,正则表达式适用于 C++11

    这是一个超高效的就地解决方案,不需要任何库并且在 C++98 中工作:

    template<typename FwdIter>
    FwdIter replace_whitespace_by_one_space(FwdIter begin, FwdIter end)
    {
        FwdIter dst = begin;
    IGNORE_LEADING_WHITESPACE:
        if (begin == end) return dst;
        switch (*begin)
        {
        case ' ':
        case '\t':
            ++begin;
            goto IGNORE_LEADING_WHITESPACE;
        }
    COPY_NON_WHITESPACE:
        if (begin == end) return dst;
        switch (*begin)
        {
        default:
            *dst++ = *begin++;
            goto COPY_NON_WHITESPACE;
        case ' ':
        case '\t':
            ++begin;
            // INTENTIONAL FALLTHROUGH
        }
    LOOK_FOR_NEXT_NON_WHITESPACE:
        if (begin == end) return dst;
        switch (*begin)
        {
        case ' ':
        case '\t':
            ++begin;
            goto LOOK_FOR_NEXT_NON_WHITESPACE;
        default:
            *dst++ = ' ';
            *dst++ = *begin++;
            goto COPY_NON_WHITESPACE;
        }
    }
    

    请注意,gotos 通常被认为在有限自动机的生成代码中是完全可以接受的,尽管在这种情况下,我必须承认代码是由我的大脑和手指生成的;)

    下面是一个示例,说明您可以如何使用建议的解决方案:

    int main()
    {
        std::string example = "\t\t\tpush \t \t42\t\t\t";
        auto new_end = replace_whitespace_by_one_space(example.begin(), example.end());
        example.erase(new_end, example.end());
        std::cout << "[" << example << "]\n";
    }
    

    【讨论】:

    • 您可以通过第二个std::regex_replace 执行ltrimrtrim 操作:"^\\s+|\\s+$"
    • 我只能使用 C++98,正则表达式适用于 C++11 吗?我错了吗?
    • @NicolasCharvozKurzawa 我将答案从 C++11 解决方案更改为 C++98 解决方案。
    • 我不能在 C++98 中使用 auto,除此之外我应该使用什么?
    • @NicolasCharvozKurzawa std::string::iterator.
    【解决方案2】:

    您可以创建一个模板修剪功能,以与remove_if类似的方式实现

    #include <string>
    #include <iterator>
    #include <iostream>
    #include <ctype.h>
    #include <sstream>
    using namespace std;
    
    template <class ForwardIterator, class OutputIterator, class UnaryPredicate>
    void trim (
      ForwardIterator first, ForwardIterator last, OutputIterator result,
      UnaryPredicate pred
    ) {
      while (first != last && pred(*first))
        first++;
      for (ForwardIterator p = last; first != last; first++) {
        if (pred(*first))
          p = first;
        else {
          if (p != last) {
            *result = *p;
            p = last;
          }
          *result = *first; 
        }
      }
    }
    
    inline bool isJunk(char c) {
      return isspace(c);
    }
    
    inline string trim_string(string s) {
      ostringstream result;
      trim(s.begin(), s.end(), ostream_iterator<char>(result, ""), isJunk);
      return result.str();
    }
    
    int main() {
      cout << trim_string(" What     the    fraaak    ") << "." << endl;
    }
    

    输出:

    What the fraaak.
    

    【讨论】:

    • 能否提供错误码?它用 g++ 编译给我。
    • test.cpp:在函数“std::string trim_string(std::string)”中:test.cpp:25:28:错误:“ostream_iterator”未在此范围内声明 trim(s .begin(), s.end(), ostream_iterator(result, ""), isJunk); ^ test.cpp:25:45: 错误: 'char' trim(s.begin(), s.end(), ostream_iterator(result, ""), isJunk); ^
    • 完美运行,但是单词前的空格呢?和之后?
    【解决方案3】:

    如果您想用一个空格替换所有连续的空格,您可以使用简单的正则表达式轻松完成。如果你的编译器支持当前标准,它应该在标准库中有正则表达式实用程序,但如果你仅限于 c++98,你可以使用外部库来代替。这是使用此类库的解决方案:

    test = boost::regex_replace(test, boost::regex("\\s+"), " ");
    

    【讨论】:

      【解决方案4】:

      对于不会使用 C++11 的朋友,这里有一个简单的非正则表达式解决方案:

      void RemoveWhitespace(std::string *str)
      {
          // all tabs to spaces
          ReplaceString(str, "\t", " ");
      
          // all double spaces to single spaces
          while (ReplaceString(str, "  ", " ") != 0); 
      
          // trim the string
          if (!s.empty())
          {
              if (s.back() == ' ') s.pop_back();
              if (s.front() == ' ') s.erase(s.begin());
          }
      }
      

      ReplaceString 可以实现为

      // returns the number of replaced substrings
      unsigned int ReplaceString(std::string &str, const std::string &search,
                                 const std::string &replace)
      {
          unsigned int count = 0;
      
          size_t pos = 0;
          while ((pos = str.find(search, pos)) != std::string::npos)
          {
              str.replace(pos, search.length(), replace);
              pos += replace.length();
              ++count;
          }
      
          return count;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-10
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多