【问题标题】:Can I strip carriage returns as they go into a `std::stringstream`?当它们进入`std::stringstream`时,我可以去掉回车吗?
【发布时间】:2012-01-17 12:32:49
【问题描述】:
struct T
{
   void eat(std::string const& segment)
   {
      buffer << segment;

      std::string sentence;
      while (std::getline(buffer, sentence))
         std::cout << "[" << sentence.size() << "]";
   }

   std::stringstream buffer;
};

int main() {
   T t;
   t.eat("A\r\nB\nC\nD");
//        ^^   ^  ^  ^
}

// Actual output:  [2][1][1][1]
// Desired output: [1][1][1][1]

我希望 std::stringstream 为我删除回车(并且不希望复制和修改 segment)。

我该怎么办?我本以为无论如何都会发生这种情况,在 Linux 上,对于文本模式的流......但也许这种机制在 file 流的逻辑中。

【问题讨论】:

  • 我想我可以一次只输入一个角色,而忽略\r。我 cba 对其进行基准测试,但我想知道这样做是否会失去任何速度。
  • 您可以使用修改后的 getline 函数,如 this question 中的函数。
  • eaten的字符串中是否可能存在其他空格?
  • @hmjd:通常不会,但我对此没有足够的信心聘请std::skipws
  • std::skipws 不是解决方案,因为它只会删除前导空格(Windows 中的 '\015' 通常会显示为尾随),并且会被 getline 等未格式化的输入函数忽略.

标签: c++ iostream line-endings


【解决方案1】:

这是 Unix 机器上读取创建的文件时的普遍问题 一台 Windows 机器。我建议在输入处进行清理 级别。

我在读取基于行的文件时发现的最佳解决方案之一是 创建一个类似的类:

class Line
{
    std::string myText;
public:
    friend std::istream& operator>>( std::istream& source, Line& dest )
    {
        std::getline( source, dest.myText );
        if ( source ) {
            dest.myText.erase( 
                std::remove( dest.myText.begin(), dest.myText.end(), '\015' ),
                dest.myText.end() );
        }
        return source;
    }

    operator std::string() const
    {
        return myText;
    }
};

您可以根据需要添加其他功能:自动类型转换 例如,在尝试匹配模板时不播放,我找到了 有用的添加朋友包装boost::regex_match

即使我不需要,我也会使用它(没有删除 '\015') 担心 Windows/Linux 的差异;它支持使用阅读线 以std::istream_iterator&lt;Line&gt; 为例。

另一种解决方案是使用过滤流缓冲区,插入 输入流。这也很简单:

class RemoveCRStreambuf : public std::streambuf
{
    std::streambuf* mySource;
    char myBuffer;  //  One char buffer required for input.
protected:
    int underflow()
    {
        int results = mySource->sbumpc();
        while ( results == '\015' ) {
            results = mySource->sbumpc();
        }
        if ( results != EOF ) {
            myBuffer = results;
            setg( &myBuffer, &myBuffer + 1, &myBuffer + 1 );
        }
        return results;
    }

public:
    RemoveCRStreambuf( std::streambuf* source )
        : mySource( source )
    {
    }
};

插入它:

std::streambuf* originalSB = source->rdbuf();
RemoveCRStreambuf newSB( originalSB );
source->rdbuf( &newSB );
//  Do input here...
source->rdbuf( originalSB );    //  Restore...

(显然,使用某种 RAII 进行恢复将是 更可取。我自己的过滤流缓冲区有一个构造函数,它采用 一个std::istream;他们也保存了一个指向 this 的指针,并恢复 streambuf 在他们的析构函数中。)

【讨论】:

    猜你喜欢
    • 2020-10-26
    • 2013-11-11
    • 1970-01-01
    • 2017-12-04
    • 2011-11-14
    • 2020-11-01
    • 1970-01-01
    • 2019-03-10
    相关资源
    最近更新 更多