2011-03-12 20 views
6

अज्ञात लंबाई की एक स्ट्रिंग को देखते हुए, आप इसे cout का उपयोग करके आउटपुट कैसे कर सकते हैं ताकि संपूर्ण स्ट्रिंग कंसोल पर टेक्स्ट के इंडेंट ब्लॉक के रूप में प्रदर्शित हो सके? (ताकि भले ही स्ट्रिंग एक नई लाइन के लिए लपेटता, दूसरी पंक्ति खरोज के समान स्तर के लिए होता है)पैराग्राफ इंडेंटिंग पैराआउट के साथ

उदाहरण:

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 very long string that will 
    wrap to the next line because it is a 
    very long string that will wrap to the 
    next line... 

संपादित करें: होमवर्क असाइनमेंट मैं पर काम कर रहा हूँ पूरा हो गया है। उपरोक्त उदाहरण के रूप में आउटपुट को स्वरूपित करने के लिए असाइनमेंट का कोई लेना-देना नहीं है, इसलिए शायद मुझे होमवर्क टैग शामिल नहीं करना चाहिए था। यह सिर्फ अपनी खुद की प्रबुद्धता के लिए है।

मुझे पता है कि मैं स्ट्रिंग में वर्णों के माध्यम से गिन सकता हूं, देखें कि जब मैं एक रेखा के अंत तक पहुंच जाता हूं, तो प्रत्येक बार रिक्त स्थान और आउटपुट-एक्स-रिक्त स्थान थूकें। मुझे यह जानने में दिलचस्पी है कि उपरोक्त को पूरा करने के लिए एक सरल, मूर्खतापूर्ण सी ++ तरीका है या नहीं।

+0

आपने अभी तक क्या प्रयास किया है? क्या आपने वह कोड लिखा है जो दिए गए पाठ को पढ़ता है? –

+0

मैंने std :: setw() का उपयोग करने का प्रयास किया है। मैंने कोड लिखा है जो दिए गए पाठ को पढ़ता है। मैं यह देखने की कोशिश कर रहा हूं कि प्रत्येक पंक्ति को स्वचालित रूप से पैड करने के लिए एक आसान तरीका है (लाइनवैपिंग से उत्पादित लाइनों सहित) वर्णों की एक निश्चित संख्या के साथ। –

+0

मुझे संभवतः होमवर्क टैग का उपयोग नहीं करना चाहिए था - मैं होमवर्क असाइनमेंट पर काम कर रहा हूं, लेकिन असाइनमेंट आउटपुट के लिए प्रयुक्त प्रारूपण से असंबंधित नहीं है। मैं सिर्फ उत्सुक था कि यह स्वरूपण कैसे पूरा किया जा सकता है। –

उत्तर

7

यहां कुछ समाधान दिए गए हैं जो काम करेंगे यदि आप शब्दों के बीच किसी भी अंतर और/या अन्य सफेद स्थान को फेंकने के इच्छुक हैं।

पहला दृष्टिकोण, जो सबसे सरल है, पाठ को istringstream में पढ़ना होगा और स्ट्रीम से शब्दों को निकालना होगा। प्रत्येक शब्द को प्रिंट करने से पहले, यह देखने के लिए जांचें कि क्या शब्द वर्तमान रेखा पर फिट होगा या नहीं, अगर यह नहीं होगा तो एक नई लाइन प्रिंट करें। यह विशेष कार्यान्वयन अधिकतम पंक्ति लंबाई से अधिक लंबे समय तक शब्दों को संभाल नहीं पाएगा, लेकिन लंबे शब्दों को विभाजित करने के लिए इसे संशोधित करना मुश्किल नहीं होगा।

#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 नाम दिया है, लेकिन यदि आप इसका उपयोग करना चाहते हैं तो आप इसे और अधिक उचित नाम दे सकते हैं। यह कार्यान्वयन सही शब्दों को सही ढंग से विभाजित करता है।

इटरेटर कार्यान्वयन थोड़ा जटिल है, उपयोग काफी सीधा है:

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

इटरेटर के वास्तविक क्रियान्वयन इस प्रकार है:

#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 समर्थन नहीं है यदि।]

क्योंकि iterators copyable होना जरूरी यह दृष्टिकोण थोड़ा मुश्किल है और हम यह सुनिश्चित करना होगा कि किसी भी शेष बफ़र पाठ केवल एक बार मुद्रित है। हम इस तथ्य पर निर्भर करते हुए ऐसा करते हैं कि किसी भी समय आउटपुट इटरेटर को लिखा जाता है, इसकी कोई प्रतियां अब उपयोग योग्य नहीं होती हैं।

+0

हम्म; अब मुझे एहसास हुआ कि मैंने "छोटे तारों को इंडेंट नहीं किया" की आवश्यकता खो दी है। उसके लिए माफ़ करना; मैं थोड़ा सा थका हुआ हो गया। हालांकि, इसे लागू करना बहुत कठिन नहीं होगा, क्योंकि आप पहले स्ट्रिंग की लंबाई का परीक्षण कर सकते हैं और यह तय कर सकते हैं कि इसे इंडेंट या अनइंडेंट प्रिंट करना है या नहीं। –

+0

क्या आप मेरे उत्तर को देखने के लिए बहुत दयालु हो सकते हैं? मैंने इसे दूसरों के बाद अच्छी तरह से पोस्ट किया, इसलिए मुझे नहीं लगता कि यह देखा गया है। मुझे विशेष रूप से दिलचस्पी होगी यदि आप जो कुछ भी चूक गए हैं उसके बारे में सोच सकते हैं (या 'बी' को संभालने के लिए एक अच्छा सुझाव है - मैंने इसके बारे में सोचा है, लेकिन मुझे इसकी ज़रूरत नहीं है, खासकर अगर आप लाइन की शुरुआत से पहले एक टैब में बैकस्पेस, आदि) –

+0

ओह, एक और बात: इंडेंटेशन के लिए, क्या आपको लगता है कि अंतरिक्ष वर्णों का उपयोग करना सबसे अच्छा है, या स्ट्रीम के लिए जो भी 'भरें' चरित्र सेट किया गया है सेवा मेरे? –

1

मुझे यकीन है कि इस है तरह से यह करने के लिए नहीं कर रहा हूँ, लेकिन अगर आप जानते हैं या स्क्रीन की चौड़ाई मान सकते हैं, तो मेरा पहला विचार स्ट्रिंग से पहले screenWidth - indent वर्ण निकालें और उन्हें पूर्ववर्ती रिक्तियों के साथ मुद्रित करने के लिए है , और जब तक आप पूरी स्ट्रिंग नहीं कर लेते तब तक ऐसा करते रहें।

1

आप हमेशा वर्णों की एक सेट संख्या के बजाय लाइन को इंडेंट करने के लिए '\t' का उपयोग कर सकते हैं, लेकिन मुझे बाहरी पुस्तकालयों को पेश किए बिना तर्क को लागू करने का कोई आसान तरीका नहीं है।

0

यह समस्या प्रत्येक पंक्ति पर बर्बाद स्थान की मात्रा को कम करने के कार्य में कम किया जा सकता है। मान लीजिए कि हमें निम्नलिखित लंबाई

{ 6,7,6,8,10,3,4,10 } 

हम अंतरिक्ष कि व्यर्थ हो जाती है जब हम उन्हें तोड़ने के बिना पिछले n शब्द की व्यवस्था है और यह एक तालिका में डाल दिया तो हम प्रिंट करने के लिए शब्दों का इष्टतम नंबर मिल सकता है की मात्रा की गणना करते हैं की बातें है वर्तमान लाइन पर आगे बढ़ रहा है।

यहां 20 वर्ण वाली विस्तृत स्क्रीन के लिए एक उदाहरण दिया गया है। इस तालिका में पहले कॉलम अंतिम शब्द की संख्या है, दूसरे स्तंभ छोर से n'th शब्द की लंबाई है और तीसरे बर्बाद न्यूनतम जगह है:

8 6 1 
7 7 7 
6 5 14 
5 8 2 
4 10 11 
3 3 1 
2 4 5 
1 10 10 

उदाहरण के लिए हम केवल एक 10 पत्र के अंतिम शब्द है जब 10 अक्षरों को बर्बाद कर दिया गया है, अगर हमारे पास 4 अक्षरों के अंत से दूसरे के साथ 2 शब्द हैं, तो हमारे पास 5 अक्षरों को बर्बाद कर दिया जाएगा (शब्दों के बीच एक स्थान) अतिरिक्त 3 अक्षर शब्द केवल एक स्थान बर्बाद हो जाएगा। एक और 10 अक्षर शब्द जोड़ना हमें 11 अक्षरों के साथ 2 लाइनों पर बर्बाद कर देता है और इसी तरह।

उदाहरण

6, 7, 5 (0) 
8, 10 (1) 
3, 4, 10 (1) 

हम पहली पंक्ति बर्बाद अंतरिक्ष पर 2 शब्द प्रिंट करना चुनते हैं वास्तव में() शो बर्बाद अंतरिक्ष में 14 नंबर का है।

6, 7 (6) 
5, 8 (6) 
10, 3, 4 (2) 
4, 10 (6) 

मुझे लगता है कि यह एक अच्छी तरह से ज्ञात समस्या है और मैंने वर्णित एल्गोरिदम गतिशील प्रोग्रामिंग का एक उदाहरण है।

4

यह अभी भी काम का एक छोटा सा (- मानक वास्तव में समर्थन नहीं करता है/उन्हें परिभाषित जैसे, indent वास्तव में एक जोड़तोड़ के रूप में लागू किया जाना चाहिए, लेकिन तर्क के साथ चालाकी कठिन हैं portably लिखने के लिए) इस्तेमाल कर सकते हैं । मेरा मानना ​​है कि इसे अभी भी नई लाइनों को संभालने के तरीके पर थोड़ा सा काम करने की ज़रूरत है, और [संपादित करें: मुझे लगता है कि मैंने वहां देखी समस्याओं को ठीक कर दिया है।] शायद कम से कम कुछ कोने के मामले हैं जो नहीं हैं सही [संपादित करें: उदाहरण के लिए, अभी, यह बैक-स्पेस का व्यवहार करता है जैसे कि यह एक सामान्य चरित्र था]।

#include <iostream> 
#include <streambuf> 
#include <iomanip> 

class widthbuf: public std::streambuf { 
public: 
    widthbuf(int w, std::streambuf* s): indent_width(0), def_width(w), width(w), sbuf(s), count(0) {} 
    ~widthbuf() { overflow('\n'); } 
    void set_indent(int w) { 
     if (w == 0) { 
      prefix.clear(); 
      indent_width = 0; 
      width = def_width; 
     } 
     else { 
      indent_width += w; 
      prefix = std::string(indent_width, ' '); 
      width -= w; 
     } 
    } 
private: 
    typedef std::basic_string<char_type> string; 

    // This is basically a line-buffering stream buffer. 
    // The algorithm is: 
    // - Explicit end of line ("\r" or "\n"): we flush our buffer 
    // to the underlying stream's buffer, and set our record of 
    // the line length to 0. 
    // - An "alert" character: sent to the underlying stream 
    // without recording its length, since it doesn't normally 
    // affect the a appearance of the output. 
    // - tab: treated as moving to the next tab stop, which is 
    // assumed as happening every tab_width characters. 
    // - Everything else: really basic buffering with word wrapping. 
    // We try to add the character to the buffer, and if it exceeds 
    // our line width, we search for the last space/tab in the 
    // buffer and break the line there. If there is no space/tab, 
    // we break the line at the limit. 
    int_type overflow(int_type c) { 
     if (traits_type::eq_int_type(traits_type::eof(), c)) 
      return traits_type::not_eof(c); 
     switch (c) { 
     case '\n': 
     case '\r': { 
         buffer += c; 
         count = 0; 
         sbuf->sputn(prefix.c_str(), indent_width); 
         int_type rc = sbuf->sputn(buffer.c_str(), buffer.size()); 
         buffer.clear(); 
         return rc; 
        } 
     case '\a': 
      return sbuf->sputc(c); 
     case '\t': 
      buffer += c; 
      count += tab_width - count % tab_width; 
      return c; 
     default: 
      if (count >= width) { 
       size_t wpos = buffer.find_last_of(" \t"); 
       if (wpos != string::npos) { 
        sbuf->sputn(prefix.c_str(), indent_width); 
        sbuf->sputn(buffer.c_str(), wpos); 
        count = buffer.size()-wpos-1; 
        buffer = string(buffer, wpos+1); 
       } 
       else { 
        sbuf->sputn(prefix.c_str(), indent_width); 
        sbuf->sputn(buffer.c_str(), buffer.size()); 
        buffer.clear(); 
        count = 0; 
       } 
       sbuf->sputc('\n'); 
      } 
      buffer += c; 
      ++count; 
      return c; 
     } 
    } 

    size_t indent_width; 
    size_t width, def_width; 
    size_t count; 
    size_t tab_count; 
    static const int tab_width = 8; 
    std::string prefix; 

    std::streambuf* sbuf; 

    string buffer; 
}; 

class widthstream : public std::ostream { 
    widthbuf buf; 
public: 
    widthstream(size_t width, std::ostream &os) : buf(width, os.rdbuf()), std::ostream(&buf) {} 
    widthstream &indent(int w) { buf.set_indent(w); return *this; } 
}; 

int main() { 
    widthstream out(30, std::cout); 
    out.indent(10) << "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.\n"; 
    out.indent(0) << "This is\tsome\tmore text that should not be indented but should still be word wrapped to 30 columns."; 
} 

ध्यान दें कि indent(0) एक विशेष मामला है। आम तौर पर इंडेंटेशन 0 पर शुरू होता है yourstream.indent(number) जहां number या तो सकारात्मक या नकारात्मक पिछले मान के सापेक्ष इंडेंटेशन समायोजित करता है।yourstream.indent(0) कुछ भी नहीं करेगा, लेकिन मैंने इंडेंटेशन को 0 (पूर्ण के रूप में) रीसेट करने के लिए इसे विशेष रूप से नियंत्रित किया है। यदि इसे गंभीर उपयोग में डाल दिया जाता है, तो मुझे यकीन नहीं है कि लंबी अवधि में सर्वश्रेष्ठ कार्य करेगा, लेकिन कम से कम डेमो के लिए यह काफी सुविधाजनक प्रतीत होता है।

+0

बहुत अच्छा। एक 'स्ट्रीमबफ'-आधारित दृष्टिकोण निश्चित रूप से 'stream_iterator' से अधिक समझ में आता है। 0 हैक की बजाय 'reset_indent (int) 'होना क्लीनर हो सकता है। मुझे '\ b' हैंडलिंग के बारे में निश्चित नहीं है: मुझे लगता है कि सबसे अधिक प्राकृतिक दृष्टिकोण बफरिंग रखना होगा जब तक कि' ओवरफ्लो' '\ r' या '\ n' प्राप्त न हो जाए, क्योंकि आप (आमतौर पर?) एक बैकस्पेस नहीं कर सकते नई लाइन, लेकिन फिर आप बहुत अनावश्यक बफरिंग कर सकते हैं। रिक्त स्थान बनाम चरित्र के बारे में यह एक अच्छा सवाल है; मुझे लगता है कि भरने वाले चरित्र का उपयोग करना अधिक "लचीला" होगा, क्योंकि आप इसे अभी भी एक स्थान पर सेट कर सकते हैं। –

संबंधित मुद्दे