Konsolenoutput in Tabellen formatieren [gelöst]
-
Moin zusammen,
ich würde gerne folgenden Array, schön sauber und geordnet in 2-4 Tabellen nebeneinander darstellen:
#include <iostream> int main() { std::string test[30] = {"test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test"}; for (int i = 0; i<30; i++){ std::cout << i << " " <<test[i] <<std::endl; } return 0; }
Wenn ich nun aber
std::cout <<i << " " <<test[i] <<"\t"
versuche, kommt nur totaler Unsinn bei raus. Ich denke, dass schwierige daran ist, dass alle Worte nicht gleich lang sind aber trotzdem in "gleichen" Tabellen dargestellt werden sollen - natürlich numerisch passend. Quasi so, nur nebeneinander:- test
- testing
- testingtest
- testtesting
- testing
- test
- testest
- testingtestest
Gruß,
-
-
Hab ich schon. Das sind doch nur fixe Lückenfüller oder?
Edit: Und fixe Abstandshalter...
Edit2:
for (int i = 0; i<30; i++){ std::cout << i << " " <<test[i] <<std::setw (4); if (i % 4 == 0){ std::cout << std::endl; } }
Die erste Tabelle stimmt, danach wird es aber relativ chaotisch. Wie gleiche ich die Wortlängen aus? Man könnte natürlich, die jeweilige Wortlänge errechnen und dann mit std::setfill gegenarbeiten, aber das wäre ein bisschen sehr kompliziert.
-
@Richard_Wunsch sagte in Konsolenoutput formatieren:
Was meinst du mit Wortlänge ausgleichen? Dafür nutzt du doch std::setw.
Irgendwie so meinte ich:
#include <iostream> #include <algorithm> #include <array> #include <iomanip> int main() { std::array<std::string, 30> v = {"test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test"}; auto result = std::max_element(v.begin(), v.end(), [](const std::string& s1, const std::string& s2){ return s1.size() < s2.size(); }); auto max = result->size() +2; for (int i = 0; i<30; i++){ std::cout << i << std::setw(max) <<v[i] <<std::endl; } return 0; }
-
Danke für deine Mühe! Wenn ich deinen Code compiliere, sieht es schon ganz gut aus, wird aber immer noch untereinander ausgegeben.
Bei meinem Versuch:
for (int i = 0; i<30; i++){ std::cout << i << " " <<test[i] <<std::setw (15); if (i % 4 == 0){ std::cout << std::endl; } }
Kommt das raus:
https://www.directupload.net/file/d/5286/rwpscbmp_png.htm
Die erste Tabelle stimmt (abgesehen von der numerischen Reihenfolge), aber alle folgenden sind durcheinander, weil die Wörter in der ersten Tabelle unterschiedlich lang sind. Gibt es eine einfach Möglichkeit das auszugleichen?
-
@Richard_Wunsch
Ach, so hab in deinem ersten Code gar nix von mehreren Spalten gesehenDann halt so (rest wie oben):
auto max = result->size() +1; for (int i = 0; i<30; i++){ std::cout << std::setw(2) << i << ' ' << v[i] << std::setw(max-v[i].size()) << ' '; if(i % 2) std::cout << '\n'; }
-
Vielen Dank! Funktioniert hervorragend. Also muss man doch den Abstand zwischen zwei Wörtern errechnen, um es vernünftig darzustellen! Wenn die Tabellen jetzt noch chronologisch kongruent wären, wäre es Perfektion. Aber so geht es auch schon sehr gut.
-
@Richard_Wunsch sagte in Konsolenoutput formatieren:
Also muss man doch den Abstand zwischen zwei Wörtern errechnen, um es vernünftig darzustellen!
Ja, sorry, hatte dich da am Anfang falsch verstanden.
-
Habe mich auch nicht gerade deutlich ausgedrückt ^^
Edit: Ah, außerdem vergleicht man auch nicht zwei Wörter, sondern sucht nur innerhalb des arrays (bzw. vectors) nach dem längsten Wort und setzt das als standard wert für std::setw, richtig?
Warum vergleichst du noch den zweitgrößten String? Würde das nicht reichen?:
auto result = std::max_element(v.begin(), v.end(), [](const std::string& s1){ return s1.size(); });
-
Falls es noch jemand interessiert: einen bestehenden array kann man mit
std::copy
in einen fixen array kopieren und mitif (i % 3 == 2)
bzw.if (i % 4 == 3)
3 oder 4 Tabellenspalten erzeugen. Siehe Code:#include <iostream> #include <algorithm> #include <array> #include <iomanip> int main() { std::string test[30] = {"test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test"}; std::array<std::string, 30> v = {}; std::copy(std::begin(test),std::end(test),std::begin(v)) ; auto result = std::max_element(v.begin(), v.end(), [](const std::string& s1, const std::string& s2){ return s1.size() < s2.size(); }); auto max = result->size() +2; for (int i = 0; i<30; i++){ std::cout << std::setw(2) << i << ' ' << v[i] << std::setw(max-v[i].size()) << ' '; if(i % 3 == 2) std::cout << '\n'; } return 0; }
Edit: Den Verweis auf
std::copy
bitte ignorieren -> siehe unten
-
Aus welchem Grund sollte man das array umkopieren?
-
@manni66
Falls er bereits vorhanden ist. Oder gibt es die
begin()
Funktion auch für "einfache" arrays?
-
@Richard_Wunsch sagte in Konsolenoutput in Tabellen formatieren [gelöst]:
@manni66
Falls er bereits vorhanden ist. Oder gibt es die
begin()
Funktion auch für "einfache" arrays?Was benutzt du denn in deinem copy?
-
@manni66
Hahaha danke für den Hinweis. Wie kann man nur solche Tomaten auf den Augen haben?
-
Noch 2 Fragen hierzu - Warum ist es nicht möglich, die Arraylänge mit einem Integer zu beschreiben?
#include <iostream> #include <algorithm> #include <array> #include <iomanip> int main() { int testArrayLength = 30; std::string test[testArrayLength = {"test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "test", "test", "test", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testtestingtest", "testtestingtesttesttestingtest", "testtest", "testing", "testingtest", "testtesting", "test", "test"}; auto result = std::max_element(std::begin(test), std::end(test), [](const std::string& s1, const std::string& s2){ return s1.size() < s2.size(); }); auto max = result->size() +2; for (int i = 0; i<30; i++){ std::cout << std::setw(2) << i << ' ' << test[i] << std::setw(max-test[i].size()) << ' '; if(i % 3 == 2) std::cout << '\n'; } return 0; }
main.cpp:14:51: error: no matching function for call to ‘begin(std::string [testArrayLength])’
Und warum ist es nicht möglich den Inhalt des Arrays erst im Nachhinein zu definieren?
#include <iostream> #include <algorithm> #include <array> #include <iomanip> int main() { std::string test[] = {}; test [0] = "test"; auto result = std::max_element(std::begin(test), std::end(test), [](const std::string& s1, const std::string& s2){ return s1.size() < s2.size(); }); auto max = result->size() +2; for (int i = 0; i<30; i++){ std::cout << std::setw(2) << i << ' ' << test[i] << std::setw(max-test[i].size()) << ' '; if(i % 3 == 2) std::cout << '\n'; } return 0; }
main.cpp:10:51: error: no matching function for call to ‘begin(std::string [0])’
Wenn ich stattdessen
std::string test[] = {""};
benutze funktioniert es - warum?
-
@Richard_Wunsch Benutze
std::vector
!Bei Arrays muss die Länge bereits während der Compilezeit feststehen. Bei deinem ersten Beispiel fehlt dir mindestens eine eckige schließende Klammer hinter
std::string test[testArrayLength
und außerdem musstestArrayLength
dafür eine Konstante sein. Alsoconst int testArrayLength = 30;
und es wäre möglich.Wenn du variabel viele Strings hast oder erst im Programmverlauf die Strings füllen willst, nimm
std::vector<std::string>
.Bei Arrays, die du gleich zuweist wie hier:
std::string test[] = {""};
wird die Länge des Arrays automatisch anhand der rechten Seite ermittelt. Dort befindet sich 1 Element. Der Code entspricht also:std::string test[1] = {""};
Das hier ist Blödsinn:
std::string test[] = {};
. Was soll das sein - ein Array der Länge 0? Also wirst du in test hier niemals etwas speichern können. Das folgendetest [0] = "test";
aus deinem Beispiel geht aber davon aus, dass das Array mindestens die Länge 1 hat. Boom!Vergiss fürs erste Arrays und sieh dir vector an!
-
@wob Auch hier vielen Dank für deine Antwort!! In meinem Kopf waren Vektoren immer mehrdimensional, weshalb ich nie darauf zurückgegriffen habe, um nur eine Zahl oder einen String zu speichern.
Die eckige Klammer war einfach nur schlampig kopiert...
Mir war nicht bewusst, dass die Arraylänge bereits beim compilen konstant feststehen muss - danke für den Hinweis. Dann macht es natürlich auch Sinn, dass ein einfacher Integer als Beschreibung nicht reicht.