缩进段落使用cout [英] Indenting Paragraph With cout

查看:131
本文介绍了缩进段落使用cout的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个未知长度的字符串,如何使用cout输出它,使整个字符串显示为控制台上缩进的文本块? (使得即使字符串换行到新行,第二行也将具有相同的缩进水平)

Given a string of unknown length, how can you output it using cout so that the entire string displays as an indented block of text on the console? (so that even if the string wraps to a new line, the second line would have the same level of indentation)

示例:

cout << "This is a short string that isn't indented." << endl;
cout << /* Indenting Magic */ << "This is a very long string that will wrap to the next line because it is a very long string that will wrap to the next line..." << endl;

所需输出:


这是一个不缩进的短字符串。

This is a short string that isn't indented.

    This is a very long string that will
    wrap to the next line because it is a
    very long string that will wrap to the
    next line...


编辑:我正在处理的家庭作业已完成。该赋值与获取输出格式与上面的例子无关,所以我可能不应该包括家庭作业标签。这只是为了我自己的启示。

The homework assignment I'm working on is complete. The assignment has nothing to do with getting the output to format as in the above example, so I probably shouldn't have included the homework tag. This is just for my own enlightment.

我知道我可以通过字符串中的字符,看到当我到一行的结尾,然后吐出一个换行符和输出-x个空格。我有兴趣知道是否有一个更简单的,惯用的C ++方法来完成上述操作。

I know I could count through the characters in the string, see when I get to the end of a line, then spit out a newline and output -x- number of spaces each time. I'm interested to know if there is a simpler, idiomatic C++ way to accomplish the above.

推荐答案

解决方案,如果你愿意抛出任何多个间距和/或其他空格之间的单词之间的工作。

Here are a couple of solutions that will work if you are willing to throw out any multiple spacing and/or other whitespace between words.

第一种方法,这是最直接的,将是将文本读入 istringstream ,并从流中提取单词。在打印每个单词之前,检查该单词是否适合当前行,如果不是,则打印换行符。这个特定的实现将不会正确处理长度大于最大行长度的字,但是将其修改为拆分长字不难。

The first approach, which is the most straightforward, would be to read the text into an istringstream and extract words from the stream. Before printing each word, check to see whether the word will fit on the current line and print a newline if it won't. This particular implementation won't handle words longer than the maximum line length correctly, but it wouldn't be difficult to modify it to split long words.

#include <iostream>
#include <sstream>
#include <string>

int main() {
    const unsigned max_line_length(40);
    const std::string line_prefix("    ");

    const std::string text(
        "Friends, Romans, countrymen, lend me your ears; I come to bury Caesar,"
        " not to praise him.  The evil that men do lives after them; The good "
        "is oft interred with their bones; So let it be with Caesar.");

    std::istringstream text_iss(text);

    std::string word;
    unsigned characters_written = 0;

    std::cout << line_prefix;
    while (text_iss >> word) {

        if (word.size() + characters_written > max_line_length) {
            std::cout << "\n" << line_prefix;
            characters_written = 0;
        }

        std::cout << word << " ";
        characters_written += word.size() + 1;
    }
    std::cout << std::endl;
}

第二个更高级的选项是编写自定义 ostream_iterator ,用于格式化您希望格式化的行。我把这个 ff_ostream_iterator 命名为有趣的格式化,但如果你想使用它,你可以命名为更合适。

A second, more "advanced" option, would be to write a custom ostream_iterator that formats lines as you expect them to be formatted. I've named this ff_ostream_iterator, for "funny formatting," but you could name it something more appropriate if you wanted to use it. This implementation does correctly split long words.

虽然迭代器的实现有点复杂,但使用非常简单:

While the iterator implementation is a bit complex, the usage is quite straightforward:

int main() {
    const std::string text(
        "Friends, Romans, countrymen, lend me your ears; I come to bury Caesar,"
        " not to praise him.  The evil that men do lives after them; The good "
        "is oft interred with their bones; So let it be with Caesar. ReallyLong"
        "WordThatWontFitOnOneLineBecauseItIsSoFreakinLongSeriouslyHowLongIsThis"
        "Word");

    std::cout << "    ========================================" << std::endl;

    std::copy(text.begin(), text.end(), 
              ff_ostream_iterator(std::cerr, "    ", 40));
}

迭代器的实际实现如下:

The actual implementation of the iterator is as follows:

#include <cctype>
#include <iostream>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>

class ff_ostream_iterator 
    : public std::iterator<std::output_iterator_tag, char, void, void, void>
{
public:

    ff_ostream_iterator() { }

    ff_ostream_iterator(std::ostream& os,
                        std::string line_prefix, 
                        unsigned max_line_length)
        : os_(&os),
          line_prefix_(line_prefix), 
          max_line_length_(max_line_length),
          current_line_length_(),
          active_instance_(new ff_ostream_iterator*(this))
    { 
        *os_ << line_prefix;
    }

    ~ff_ostream_iterator() {
        if (*active_instance_ == this)
            insert_word();
    }

    ff_ostream_iterator& operator=(char c) {
        *active_instance_ = this;
        if (std::isspace(c)) {
            if (word_buffer_.size() > 0) {
                insert_word();
            }
        }
        else {
            word_buffer_.push_back(c);
        }
        return *this;
    }

    ff_ostream_iterator& operator*()     { return *this; }
    ff_ostream_iterator& operator++()    { return *this; }
    ff_ostream_iterator  operator++(int) { return *this; }


private:

    void insert_word() {
        if (word_buffer_.size() == 0)
            return; 

        if (word_buffer_.size() + current_line_length_ <= max_line_length_) {
            write_word(word_buffer_);
        }
        else { 
            *os_ << '\n' << line_prefix_;

            if (word_buffer_.size() <= max_line_length_) {
                current_line_length_ = 0;
                write_word(word_buffer_);
            }
            else {
                for (unsigned i(0);i<word_buffer_.size();i+=max_line_length_) 
                {
                    current_line_length_ = 0;
                    write_word(word_buffer_.substr(i, max_line_length_));
                    if (current_line_length_ == max_line_length_) {
                        *os_ << '\n' << line_prefix_;
                    }
                }
            }
        }

        word_buffer_ = "";
    }

    void write_word(const std::string& word) {
        *os_ << word;
        current_line_length_ += word.size();
        if (current_line_length_ != max_line_length_) {
            *os_ << ' ';
            ++current_line_length_;
        }
    }

    std::ostream* os_;
    std::string word_buffer_;

    std::string line_prefix_;
    unsigned max_line_length_;
    unsigned current_line_length_;

    std::shared_ptr<ff_ostream_iterator*> active_instance_;
};

[如果您复制并粘贴此代码段和 main 从上面,它应该编译和运行如果你的编译器支持C ++ 0x std :: shared_ptr ;你可以用 boost :: shared_ptr std :: tr1 :: shared_ptr 替换,如果你的编译器没有C ++ 0x支持。]

[If you copy and paste this code snippet and the main from above it, it should compile and run if your compiler supports the C++0x std::shared_ptr; you can replace that with boost::shared_ptr or std::tr1::shared_ptr if your compiler doesn't have C++0x support yet.]

这种方法有点棘手,因为迭代器必须是可复制的,我们必须确保任何剩余的缓冲文本一旦。我们这样做的依赖于任何时候输出迭代器写入的事实,它的任何副本不再可用。

This approach is a bit tricky because iterators have to be copyable and we have to be sure that any remaining buffered text is only printed exactly once. We do this by relying on the fact that any time an output iterator is written to, any copies of it are no longer usable.

这篇关于缩进段落使用cout的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆