Compte tenu d'une chaîne de longueur inconnue, comment pouvez-vous la produire à l'aide de COUT afin que toute la chaîne s'affiche en tant que bloc de texte en retrait sur la console? (de sorte que même si la chaîne enveloppe une nouvelle ligne, la deuxième ligne aurait le même niveau d'indentation)
Exemple: P> et la sortie souhaitée: Ceci est une courte chaîne qui n'est pas indentée. P>
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...
5 Réponses :
Je ne suis pas sûr que ce soit le moyen em> de le faire, mais si vous savez ou pouvez assumer la largeur de l'écran, ma première pensée est de supprimer le premier ScreenWidth - indentement Code> Chars de la chaîne et imprimez-les avec les espaces précédents et continuez à le faire jusqu'à ce que vous ayez terminé la chaîne entière. P>
Vous pouvez toujours utiliser '\ t' code> pour indenter la ligne au lieu d'un nombre défini de caractères, mais je ne connais aucun moyen plus simple de mettre en œuvre la logique sans introduire des bibliothèques externes. P>
Voici quelques solutions qui fonctionnent si vous êtes prêt à jeter un espacement multiple et / ou d'autres espaces entre mots.
La première approche, qui est la plus simple, serait de lire le texte dans un istringstream code> et extrait des mots du flux. Avant d'imprimer chaque mot, vérifiez si le mot s'adapte à la ligne actuelle et imprimera une nouvelle ligne si elle ne le fera pas. Cette mise en œuvre particulière ne traitera pas correctement les mots plus longs que la longueur maximale de la ligne, mais il ne serait pas difficile de le modifier pour diviser les mots longs. P>
#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_;
};
Hmm; Je réalise maintenant que j'ai perdu la trace des «cordes courtes ne sont pas indentées». Désolé pour ça; J'ai un peu détourné. Cela ne serait pas trop difficile à mettre en œuvre, car vous pouvez simplement tester la longueur de la chaîne à l'avance et décider de l'imprimer en retrait ou indenté.
Pourriez-vous être si gentille de jeter un coup d'œil à ma réponse? Je l'ai bien posté après la plupart des autres, alors je ne pense pas que cela soit fouillé. Je serais particulièrement intéressé si vous pouvez penser à tout ce que j'ai manqué (ou si vous avez une bonne suggestion à gérer «\ B» - j'y ai pensé, mais je ne suis pas sûr de tout ce qui est nécessaire, surtout si vous revenez dans un onglet, après le début de la ligne, etc.)
Oh, une autre chose: pour l'indentation, pensez-vous qu'il est préférable d'utiliser des caractères spatiaux, ou quel que soit le caractère "Remplir" pour le flux a été réglé?
@Jerry: C'est une très bonne idée, en utilisant un streambuf code personnalisé>!
Je ne voulais pas impliquer que les "chaînes courtes ne soient pas indentées" exigences. J'ai inclus la chaîne non indentée, alors l'indentation de la chaîne suivante était apparente. Merci pour votre réponse!
Ce problème peut être réduit à une tâche de minimiser la quantité d'espace gaspillé sur chaque ligne.
Supposons que nous ayons des mots de longueurs suivants si nous calculons la quantité d'espace qui sera gaspillée lorsque nous organiserons les nords derniers sans les casser et la mettre dans une table, nous pouvons trouver un nombre optimal de mots à imprimer sur la ligne actuelle à l'avenir. p> Voici un exemple de 20 caractères de caractères. Dans ce tableau, la première colonne est le nombre de derniers mots, la deuxième colonne est la longueur du mot N'th de l'extrémité et de la troisième est l'espace minimum gaspillé: p> par exemple lorsque nous Avoir un dernier mot de 10 lettres 10 lettres 10 lettres sont gaspillés, si nous avons 2 mots avec deuxièmes de la fin de la fin de 4 caractères, nous aurons 5 lettres gaspillées (un espace entre les mots), un mot supplémentaire de 3 lettres ne laissera que des espaces gaspillés. Ajout d'un autre mot de 10 lettres nous laisse avec 11 lettres gaspillées sur 2 lignes et ainsi de suite. P> exemple p> Si nous choisissons d'imprimer 2 mots sur La première ligne gaspille de l'espace est en effet 14. Nombres dans () Afficher l'espace gaspillé. P> 6, 7 (6)
5, 8 (6)
10, 3, 4 (2)
4, 10 (6)
Ceci pourrait toujours utiliser un peu de travail (par exemple, le indent code> devrait probablement être implémenté comme manipulateur, mais les manipulateurs avec des arguments sont durs em> pour écrire de manière portante - La norme ne supporte pas vraiment / les définir). Il y a probablement au moins deux cas de coin qui ne sont pas parfaits (par exemple, il traite le dos comme s'il s'agissait d'un caractère normal).
#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.";
}
Très agréable. A code> streambuf CODE> APPROCHE BASED a définitivement plus de sens qu'un stream_iterator code>. Il pourrait être plus propre d'avoir un
réinitialiser_indent (int) code> au lieu du piratage 0. Je ne suis pas sûr de
\ b code> Traitement: je suppose que l'approche la plus naturelle serait de garder la mémoire tampon jusqu'à ce que
Overflow code> obtient un
\ r code> ou < Code> \ n code> Depuis que vous (généralement?) Impossible de retourner sur une nouvelle ligne, mais vous risquez de faire beaucoup de tampon inutile. C'est une bonne question sur les espaces contre le caractère de remplissage; Je suppose que l'utilisation du caractère de remplissage serait plus "flexible", car vous pouviez toujours régler cela dans un espace.
Qu'avez-vous essayé jusqu'à présent? Avez-vous écrit le code qui lit le texte donné?
J'ai essayé d'utiliser STD :: Setw (). J'ai écrit le code qui lit le texte donné. J'essaie de voir s'il existe un moyen simple d'obtenir la cessation de céder automatiquement chaque ligne (y compris des lignes produites à partir de ligne de ligne) avec un nombre donné de caractères.
Je n'aurais peut-être pas dû utiliser l'étiquette des devoirs - je travaille sur une mission de devoirs, mais l'affectation n'est pas liée au formatage utilisé pour la sortie. J'étais juste curieux de savoir comment ce formatage pourrait être accompli.
Un problème que vous trouverez est qu'il n'ya aucun moyen d'obtenir la largeur de la console de la bibliothèque C ++. Vous devriez faire des hypothèses à ce sujet. (80 caractères semblent être assez standard.) Vous voudrez également voir combien de temps le prochain "mot" est et comparer cela à la quantité de pièce que vous avez dans la ligne actuelle. Insérez la pause de la ligne si vous n'avez pas assez de place.
question cool. Merci.