如何修改传递给cout的字符串?

3
假设我想对传递给cout(或另一个ostream)的每个字符串进行rot13处理,例如cout<<"Foo Bar Baz.;"(甚至cout<<rot13<<"Foo Bar Baz.";),输出Sbb One Onm.
我该怎么做呢?
(我的第一个想法是用派生自streambuf的类替换cout的streambuf,让它完成所有工作。但是由于原始streambuf负责将东西定向到控制台...这根本行不通。)
2个回答

3
你可以编写自己的流,重载char*、std::string和其他类型的<<操作符,并打印转换后的文本。
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>

using namespace std;

class ostream_rot13 : public basic_ostream <char, char_traits<char> >
{
public:
    ostream_rot13(std::basic_streambuf<char, char_traits<char> >* sb) 
    : basic_ostream<char, char_traits<char> >(sb) {}

    ostream_rot13& operator<<(const char* text)
    {
        std::string s(text);

        int rot=13;
        std::transform(std::begin(s), std::end(s), ostream_iterator<char>(*this), [rot] (char c) { 
            if(c >= 'a' && c <= 'z')
                return 'a' + (c + rot - 'a') % 26;
            else if(c >= 'A' && c <= 'Z')
                return 'A' + (c + rot - 'A') % 26;

            return (int)c;
        });

        return *this;
    }
};

下一步是声明一个此类型的全局变量,然后定义一个宏,用新变量替换cout。
ostream_rot13 cout_rot13(std::cout.rdbuf());

#define cout cout_rot13

接下来,所有的cout实例都将变为cout_rot13。

int main() 
{
    cout << "Foo Bar Baz";

    return 0;
}

供参考:仅在启用C++11时编译。) 与使用#define不同,我会重载ostream_rot13的<<,以便cout<<ostream_rot13_obj设置ostream_rot13_obj的缓冲区并返回ostream_rot_13_obj。现在,如果rot13是一个ostream_rot13对象,则cout<<rot13<<"Foo Bar Baz."将给我所需的结果。(我刚注意到我的问题不允许这样做;我会修复它。)这个答案的一个问题是操纵器停止工作(无法使用您的代码进行cout<<endl;或使用我的修改进行cout<<rot13<<endl;)。 - Anubhav C

1

你能否将cout的streambuf包装在自己的streambuf中,将所有调用转发到被包装的buffer中?
在转发“put”调用到被包装的streambuf之前,只需要进行一些编码即可。

虽然只是为了一点点rot13而做很多工作。


我喜欢这个想法,但由于某些原因它无法工作 - 我猜测是因为当我执行cout<<"Some string";时并没有实际调用putc()。我将尝试重载sync()和overflow()来看看是否有任何区别。 - Anubhav C

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