Skip to content
Snippets Groups Projects
Commit 4a5566ee authored by Tom Tiltmann's avatar Tom Tiltmann
Browse files

initial

parent cf324a9b
Branches
No related tags found
No related merge requests found
{
"additionalFiles": "..,..",
"builtInLibrariesFolders": "/Applications/Arduino.app/Contents/Java/libraries",
"builtInToolsFolders": "/Applications/Arduino.app/Contents/Java/tools-builder,/Applications/Arduino.app/Contents/Java/hardware/tools/avr,/Users/to/Library/Arduino15/packages",
"compiler.optimization_flags": "",
"customBuildProperties": "build.path=/Users/to/sciebo/TT_Arduino/2_projects/serialTable/.build,build.warn_data_percentage=75,runtime.tools.arduinoOTA.path=/Users/to/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0,runtime.tools.arduinoOTA-1.3.0.path=/Users/to/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0,runtime.tools.avr-gcc.path=/Users/to/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7,runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino7.path=/Users/to/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7,runtime.tools.avrdude.path=/Users/to/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17,runtime.tools.avrdude-6.3.0-arduino17.path=/Users/to/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17",
"fqbn": "arduino:avr:mega:cpu=atmega2560",
"hardwareFolders": "/Applications/Arduino.app/Contents/Java/hardware,/Users/to/Library/Arduino15/packages",
"otherLibrariesFolders": "/Users/to/sciebo/TT_Arduino/libraries",
"runtime.ide.version": "10819",
"sketchLocation": "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/serialTable.ino"
}
\ No newline at end of file
File added
[
{
"Sourcefile": null,
"Include": "",
"Includepath": "/Users/to/Library/Arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino"
},
{
"Sourcefile": null,
"Include": "",
"Includepath": "/Users/to/Library/Arduino15/packages/arduino/hardware/avr/1.8.6/variants/mega"
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/.build/sketch/serialTable.ino.cpp",
"Include": "AUnit.h",
"Includepath": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src"
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/.build/sketch/serialTable.ino.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/Assertion.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/Compare.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/FCString.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/MetaAssertion.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/Printer.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/Test.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/TestAgain.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/TestOnce.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/TestRunner.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/print64.cpp",
"Include": "",
"Includepath": null
},
{
"Sourcefile": "/Users/to/sciebo/TT_Arduino/libraries/AUnit/src/aunit/string_util.cpp",
"Include": "",
"Includepath": null
}
]
\ No newline at end of file
# 1 "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/serialTable.ino"
# 2 "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/serialTable.ino" 2
# 3 "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/serialTable.ino" 2
# 4 "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/serialTable.ino" 2
void setup()
{
// Initialisieren der seriellen Verbindung
Serial.begin(115200);
// Definieren der Kopfzeilen und Spaltenbreiten für 8 Spalten
const char *headers[] = {"Vorname", "Nachname", "Alter", "Stadt", "Beruf", "Unternehmen", "Hobby", "Bemerkung"};
int columnWidths[] = {10, 15, 5, 10, 10, 15, 10, 20};
SerialTable table(headers, columnWidths, 8);
table.printHeader();
// Erstellen von 20 Zeilen mit unterschiedlichen Einträgen
char *rows[20][8] = {
{"Alice", "Wonderland", "30", "Köln", "Ingenieur", "FirmaX", "Schwimmen", "Keine"},
{"Bob", "Builder\nJr", "35", "Berlin", "Architekt", "Architektur AG", "Bauen", "Sehr erfahren"},
{"Charlie", "Brown", "28", "Hamburg", "Designer", "Die Design", "Zeichnen", "Mag Karikaturen"},
{"David", "Tennant", "40", "München", "Schauspieler", "Freiberufler", "Lesen", "Doktor gewesen"},
{"Emma", "Watson", "33", "Frankfurt", "Schauspielerin", "Independent", "Yoga", "Bekannt aus Filmen"},
{"Frank", "Herbert", "45", "Stuttgart", "Autor", "Ein Verlag", "Schreiben", "Bücher geschrieben"},
{"Grace", "Hopper", "50", "Berlin", "Programmiererin", "Tech Corp", "Informatik", "Pionierin"},
{"Hugo", "Strange", "60", "Leipzig", "Psychiater", "Gesundheits GmbH", "Philosophie", "Ruhestand"},
{"Irene", "Adler", "29", "Dresden", "Detektivin", "Privat", "Abenteuer", "Scharfsinnig"},
{"John", "Doe", "49", "Bremen", "Buchhalter", "Kontorechner", "Radfahren", "Gewissenhaft"},
{"Klara", "Kühn", "39", "Hannover", "Lehrerin", "Schule ABC", "Lesen", "Einfühlsam"},
{"Lenny", "Small", "25", "Koblenz", "Musiker", "Orchester", "Gitarre", "Kreativ"},
{"Mona", "Lisa", "33", "Siegen", "Malerin", "Kunsthaus", "Kunst", "Geheimnisvoll"},
{"Nina", "Simone", "30", "Essen", "Sängerin", "Soul Musik", "Musik", "Talentiert"},
{"Oliver", "Twist", "19", "Potsdam", "Student", "Uni XY", "Fußball", "Engagiert"},
{"Pam", "Beesly", "32", "Wuppertal", "Sekretärin", "Dunder Mifflin", "Malen", "Freundlich"},
{"Quinn", "Fabray", "26", "Magdeburg", "Designer", "Agentur XYZ", "Tanzen", "Kreativ"},
{"Ron", "Swanson", "55", "Bielefeld", "Verwalter", "Rathaus", "Holzarbeiten", "Direkt"},
{"Sophia", "Loren", "70", "Osnabrück", "Schauspielerin", "Independent", "Kochen", "Ikonisch"},
{"Tom", "Hanson", "36", "Regensburg", "Polizist", "Polizei", "Jagen", "Schützend"},
};
// Drucke die Zeilen
for (int i = 0; i < 20; ++i)
{
table.printRow(rows[i]);
}
}
void loop()
{
//TestRunner::run();
}
#line 1 "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/SerialTable.h"
#ifndef SERIALTABLE_H
#define SERIALTABLE_H
#include <Arduino.h>
class SerialTable
{
public:
SerialTable(const char *headers[], const int columnWidths[], size_t size)
: headers(headers), columnWidths(columnWidths), size(size) {}
// Diese Methode gibt den Header an die serielle Schnittstelle aus
void printHeader()
{
String header = buildHeader();
Serial.print(header);
}
String buildHeader()
{
return buildLine('-') + buildRow(const_cast<char **>(headers), '='); // Kopfzeile mit '='
}
void printRow(char **t_row)
{
String row = buildRow(t_row);
Serial.print(row);
}
String buildRow(char **t_row, char line = '-')
{
String output;
char buffer[256];
int maxLines = 1; // Maximale Anzahl Zeilen über alle Spalten
// Erste Phase: Teile jede Zelle in Zeilen und finde maximale Zeilenzahl
for (size_t i = 0; i < size; ++i)
{
if (truncateText)
{
truncateToColumnWidth(t_row[i], columnWidths[i], buffer);
}
else
{
splitStringByLength(t_row[i], columnWidths[i], buffer);
}
// Zähle Zeilen in dieser Zelle
int lineCount = 1;
for (size_t j = 0; j < displayLength(buffer); j++)
{
if (buffer[j] == '\n')
lineCount++;
}
if (lineCount > maxLines)
maxLines = lineCount;
}
// Zweite Phase: Baue die Zeilen auf
for (int line = 0; line < maxLines; line++)
{
output += "|";
// Gehe durch jede Spalte
for (size_t col = 0; col < size; ++col)
{
if (truncateText)
{
truncateToColumnWidth(t_row[col], columnWidths[col], buffer);
}
else
{
splitStringByLength(t_row[col], columnWidths[col], buffer);
}
// Finde die aktuelle Zeile für diese Spalte
char *currentLine = buffer;
int currentLineNum = 0;
char tempBuffer[256] = "";
while (currentLineNum < line)
{
char *newline = strchr(currentLine, '\n');
if (newline == NULL)
{
currentLine = "";
break;
}
currentLine = newline + 1;
currentLineNum++;
}
// Extrahiere die Zeile bis zum nächsten \n oder Ende
int j = 0;
while (currentLine[j] && currentLine[j] != '\n')
{
tempBuffer[j] = currentLine[j];
j++;
}
tempBuffer[j] = '\0';
// Berechne die tatsächliche Anzeigelänge
int printedLength = displayLength(tempBuffer);
// Füge den Inhalt und die fehlenden Leerzeichen hinzu
output += tempBuffer;
int spacesToAdd = columnWidths[col] - printedLength;
for (int k = 0; k < spacesToAdd; k++)
{
output += " ";
}
output += "|";
}
output += "\n";
}
// Füge die Trennlinie hinzu
output += buildLine(line);
return output;
}
void setTruncateText(bool value)
{
truncateText = value;
}
public: // private:
const char **headers;
const int *columnWidths;
size_t size;
bool truncateText = false;
static int displayLength(const char *text)
{
int length = 0;
for (int i = 0; text[i] != '\0'; ++i)
{
if ((text[i] & 0xC0) != 0x80)
{ // Überspringe UTF-8 Fortsetzungsbytes
length++;
}
}
return length;
}
static void safeStringCopy(char *dest, const char *src, size_t bufferSize)
{
if (strlen(src) >= bufferSize)
{
strncpy(dest, src, bufferSize - 1);
dest[bufferSize - 1] = '\0'; // NULL-termination sichergestellt
}
else
{
strcpy(dest, src);
}
}
static void replaceUmlauts(char *text)
{
// UTF-8 Codes für Umlaute (hex): ä(c3 a4) ö(c3 b6) ü(c3 bc) Ä(c3 84) Ö(c3 96) Ü(c3 9c) ß(c3 9f)
struct UmlautPair
{
unsigned char bytes[2]; // UTF-8 bytes
const char *replacement;
};
const UmlautPair pairs[] = {
{{0xc3, 0xa4}, "ae"}, // ä
{{0xc3, 0xb6}, "oe"}, // ö
{{0xc3, 0xbc}, "ue"}, // ü
{{0xc3, 0x84}, "Ae"}, // Ä
{{0xc3, 0x96}, "Oe"}, // Ö
{{0xc3, 0x9c}, "Ue"}, // Ü
{{0xc3, 0x9f}, "ss"} // ß
};
const int numPairs = sizeof(pairs) / sizeof(pairs[0]);
size_t maxOutputLength = strlen(text) * 2 + 1;
char *buffer = (char *)malloc(maxOutputLength);
if (!buffer)
return;
int k = 0; // Position im Ausgabepuffer
int i = 0; // Position im Eingabetext
while (text[i] != '\0')
{
bool replaced = false;
// Prüfe auf UTF-8 Sequenz
if ((unsigned char)text[i] == 0xc3 && text[i + 1] != '\0')
{
for (int j = 0; j < numPairs; ++j)
{
if ((unsigned char)text[i] == pairs[j].bytes[0] &&
(unsigned char)text[i + 1] == pairs[j].bytes[1])
{
// Kopiere Ersetzung
const char *replacement = pairs[j].replacement;
for (int r = 0; replacement[r] != '\0' && k < maxOutputLength - 1; ++r)
{
buffer[k++] = replacement[r];
}
replaced = true;
i += 2; // Überspringe beide UTF-8 Bytes
break;
}
}
}
if (!replaced && k < maxOutputLength - 1)
{
buffer[k++] = text[i++];
}
}
buffer[k] = '\0';
strcpy(text, buffer);
free(buffer);
}
// Neue Version von splitStringByLength
static void splitStringByLength(const char *input, int L, char *output)
{
int len = strlen(input);
int outputIndex = 0;
int currentLength = 0;
for (int i = 0; i < len; ++i)
{
// Kopiere das aktuelle Zeichen zu Ausgabe
unsigned char curr = input[i];
output[outputIndex++] = curr;
// UTF-8-Handling: Überspringe zusätzliche Bytes für ein Multibyte-Zeichen
if ((curr & 0x80) != 0)
{
// Wenn das höchste Bit gesetzt ist, haben wir ein Multibyte-Zeichen
while ((input[i + 1] & 0xC0) == 0x80)
{
output[outputIndex++] = input[++i];
}
}
currentLength++;
// Wenn die maximale Länge erreicht ist und das nächste Zeichen kein newline ist
if (currentLength == L && i + 1 < len && input[i + 1] != '\n')
{
output[outputIndex++] = '\n';
currentLength = 0;
}
}
output[outputIndex] = '\0'; // Beende den String
}
void truncateToColumnWidth(const char *input, int width, char *output)
{
int len = strlen(input);
if (len > width)
{
width = (width > 3) ? width - 3 : width;
strncpy(output, input, width);
strcpy(output + width, "...");
}
else
{
strcpy(output, input);
}
}
size_t calculateMaxLines(char **t_row)
{
size_t maxLines = 0;
for (size_t i = 0; i < size; ++i)
{
const char *text = t_row[i];
size_t textLength = strlen(text);
size_t lines = 1;
for (size_t j = 0; j < textLength; ++j)
{
if (text[j] == '\n')
{
++lines;
}
}
maxLines = max(maxLines, lines);
}
return maxLines;
}
const char *getRowSegment(const char *text, int width, size_t line, char *buffer)
{
size_t textLength = strlen(text);
size_t lineStart = 0;
size_t currentLine = 0;
buffer[0] = '\0';
for (size_t i = 0; i < textLength; ++i)
{
if (currentLine == line)
{
lineStart = i;
break;
}
if (text[i] == '\n' || (i > 0 && (i % width) == 0))
{
++currentLine;
}
}
if (lineStart >= textLength || currentLine != line)
{
return buffer;
}
size_t charCount = 0;
for (size_t i = lineStart; i < textLength && charCount < width; ++i)
{
if (text[i] == '\n')
{
break;
}
buffer[charCount++] = text[i];
}
buffer[charCount] = '\0';
return buffer;
}
String buildLine(char lineChar)
{
String line;
for (size_t i = 0; i < size; ++i)
{
line += '+';
for (int j = 0; j < columnWidths[i]; ++j)
{
line += lineChar;
}
}
line += "+\n";
return line;
}
};
#endif // SERIALTABLE_H
\ No newline at end of file
#line 1 "/Users/to/sciebo/TT_Arduino/2_projects/serialTable/UnitTests.h"
#include <AUnit.h>
#include "SerialTable.h"
using namespace aunit;
test(SplitStringNoNewlines)
{
char input[] = "This is a test string";
int length = 5;
char expectedOutput[] = "This \nis a \ntest \nstrin\ng";
char actualOutput[256] = {0}; // Ausreichend großer Puffer
SerialTable::splitStringByLength(input, length, actualOutput);
// Überprüfung der Länge der Strings
assertEqual(strlen(expectedOutput), strlen(actualOutput));
/*
// Zusätzliche Debug-Ausgabe, um Hex-Werte zu sehen
for (size_t i = 0; i < strlen(actualOutput); ++i)
{
Serial.print("Expected: ");
Serial.print((int)expectedOutput[i]);
Serial.print(", Actual: ");
Serial.println((int)actualOutput[i]);
}
*/
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 2: Eingabe mit existierenden Zeilenumbrüchen
test(SplitStringWithNewlines)
{
char input[] = "This\nis\na\ntest";
int length = 4;
char expectedOutput[] = "This\nis\na\ntest";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 3: Länge größer als Eingabetext
test(SplitStringLengthGreaterThanText)
{
char input[] = "Short";
int length = 10;
char expectedOutput[] = "Short";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 4: Genau passende Länge
test(SplitStringExactLength)
{
char input[] = "Lengthy";
int length = 7;
char expectedOutput[] = "Lengthy";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 5: Länge von 1
test(SplitStringLengthOfOne)
{
char input[] = "One";
int length = 1;
char expectedOutput[] = "O\nn\ne";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 6: Leerer Eingabestring
test(SplitStringEmptyInput)
{
char input[] = "";
int length = 5;
char expectedOutput[] = "";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Erstelle eine Hilfsfunktion für replaceUmlauts-Tests
test(replaceUmlautsTest)
{
char text1[] = "Köln";
SerialTable::replaceUmlauts(text1);
assertEqual("Koeln", text1);
char text2[] = "München";
SerialTable::replaceUmlauts(text2);
assertEqual("Muenchen", text2);
char text3[] = "Straße";
SerialTable::replaceUmlauts(text3);
assertEqual("Strasse", text3);
}
// Erstelle eine Hilfsfunktion für truncateTextTest
test(truncateTextTest)
{
char buffer[20];
SerialTable table(nullptr, nullptr, 0);
// Fall: Text passt in die Spaltenbreite
strcpy(buffer, "Hello");
table.truncateToColumnWidth(buffer, 10, buffer);
assertEqual("Hello", buffer);
// Fall: Text wird abgeschnitten
strcpy(buffer, "HelloWorld!");
table.truncateToColumnWidth(buffer, 5, buffer);
assertEqual("He...", buffer);
}
test(buildHeaderTest1)
{
// Definiere header mit char*-Zeigern
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
// Verwende buildHeader, um den Header-String zu erhalten
String header = table.buildHeader();
// Gib den Header über Serial aus
Serial.print(header);
Serial.flush();
// Erwartete Ausgabe des Headers
String expectedHeader =
"+----------+-----+----------+\n"
"|Name |Age |City |\n"
"+==========+=====+==========+\n";
// Vergleiche den erzeugten Header mit dem erwarteten Header
assertEqual(expectedHeader, header);
}
test(buildHeaderTest2)
{
// Definiere header mit char*-Zeigern
const char *headers[] = {"NameName Name", "Age Age Age", "CityCityCity"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
// Verwende buildHeader, um den Header-String zu erhalten
String header = table.buildHeader();
// Gib den Header über Serial aus
Serial.print(header);
Serial.flush();
// Erwartete Ausgabe des Headers
String expectedHeader =
"+----------+-----+----------+\n"
"|NameName N|Age A|CityCityCi|\n"
"|ame |ge Ag|ty |\n"
"| |e | |\n"
"+==========+=====+==========+\n";
// Vergleiche den erzeugten Header mit dem erwarteten Header
assertEqual(expectedHeader, header);
}
test(buildHeaderTest3)
{
// Definiere header mit char*-Zeigern
const char *headers[] = {"ä123", "ö123", "ü123"};
const int columnWidths[] = {4, 4, 4};
SerialTable table(headers, columnWidths, 3);
// Verwende buildHeader, um den Header-String zu erhalten
String header = table.buildHeader();
// Gib den Header über Serial aus
Serial.print(header);
Serial.flush();
// Erwartete Ausgabe des Headers
String expectedHeader =
"+----+----+----+\n"
"|ä123|ö123|ü123|\n"
"+====+====+====+\n";
// Vergleiche den erzeugten Header mit dem erwarteten Header
assertEqual(expectedHeader, header);
}
test(printHeaderTest)
{
// Verwende char*-Array statt String-Array
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
table.printHeader();
Serial.flush();
// Placeholder assertion, Verwendung eines Serial Monitor Tools empfohlen
assertTrue(true);
}
test(buildRowTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"Alice", "30", "Wonderland"};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"|Alice |30 |Wonderland|\n"
"+----------+-----+----------+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(printRowWithMultipleLinesTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 5};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"Alice", "30", "Wonderland"};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"|Alice |30 |Wonde|\n"
"| | |rland|\n"
"+----------+-----+-----+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(printRowWithLongTextTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"A very long name", "12345", "A very long city name"};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"|A very lon|12345|A very lon|\n"
"|g name | |g city nam|\n"
"| | |e |\n"
"+----------+-----+----------+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(printEmptyRowTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"", "", ""};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"| | | |\n"
"+----------+-----+----------+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(DisplayLengthBasic) {
assertEqual(5, SerialTable::displayLength("Hello"));
}
test(DisplayLengthWithSpace) {
assertEqual(11, SerialTable::displayLength("Hello World"));
}
test(DisplayLengthWithUmlauts) {
// "Müller" in UTF-8 hat eine Länge von 6 Zeichen (ä zählt als 1 Zeichen)
assertEqual(6, SerialTable::displayLength("Müller"));
}
test(DisplayLengthOnlyUmlauts) {
// "äöü" in UTF-8 sollten jeweils als ein Zeichen zählen
assertEqual(3, SerialTable::displayLength("äöü"));
}
test(DisplayLengthUTF8Emojis) {
// "😀😃😄" Emojis können mehrere Bytes haben, prüfen ob jedes nur als ein Zeichen gezählt wird
assertEqual(3, SerialTable::displayLength("😀😃😄"));
}
test(DisplayLengthWithNewline) {
// "Hello\nWorld" hat eine Länge von 11 Zeichen, da \n als einzelnes Zeichen zählt
assertEqual(11, SerialTable::displayLength("Hello\nWorld"));
}
test(DisplayLengthEmptyString) {
// Ein leerer String sollte eine Länge von 0 haben
assertEqual(0, SerialTable::displayLength(""));
}
test(DisplayLengthSpaces) {
// " " hat eine Länge von 3 Leerzeichen
assertEqual(3, SerialTable::displayLength(" "));
}
# Allgemeine VSCode-Einstellungen
.vscode/
*.code-workspace
# ESP32 spezifische Dateien
build/
*.elf
*.bin
*.map
*.hex
*.o
sdkconfig
sdkconfig.old
partition_table.csv
partition_table.bin
# Temporäre Dateien
*.log
*.tmp
*.bak
*.swp
*.swo
*.DS_Store
*.pyc
__pycache__/
*.d
*.lst
# Arduino Core (falls verwendet)
*.ino.*
*.cpp~
*.h~
# Debugging und Flashing
flash_project_args
build.log
flash.log
# PlattformIO (falls genutzt)
.pio/
.env
.clangd/
ipch/
project_config.json
# Betriebssystem-spezifische Dateien
Thumbs.db
Desktop.ini
# Andere IDEs (falls versehentlich hinzugefügt)
.idea/
*.iml
#ifndef SERIALTABLE_H
#define SERIALTABLE_H
#include <Arduino.h>
class SerialTable
{
public:
SerialTable(const char *headers[], const int columnWidths[], size_t size)
: headers(headers), columnWidths(columnWidths), size(size) {}
// Diese Methode gibt den Header an die serielle Schnittstelle aus
void printHeader()
{
String header = buildHeader();
Serial.print(header);
}
String buildHeader()
{
return buildLine('-') + buildRow(const_cast<char **>(headers), '='); // Kopfzeile mit '='
}
void printRow(char **t_row)
{
String row = buildRow(t_row);
Serial.print(row);
}
String buildRow(char **t_row, char line = '-')
{
String output;
char buffer[256];
int maxLines = 1; // Maximale Anzahl Zeilen über alle Spalten
// Erste Phase: Teile jede Zelle in Zeilen und finde maximale Zeilenzahl
for (size_t i = 0; i < size; ++i)
{
if (truncateText)
{
truncateToColumnWidth(t_row[i], columnWidths[i], buffer);
}
else
{
splitStringByLength(t_row[i], columnWidths[i], buffer);
}
// Zähle Zeilen in dieser Zelle
int lineCount = 1;
for (size_t j = 0; j < displayLength(buffer); j++)
{
if (buffer[j] == '\n')
lineCount++;
}
if (lineCount > maxLines)
maxLines = lineCount;
}
// Zweite Phase: Baue die Zeilen auf
for (int line = 0; line < maxLines; line++)
{
output += "|";
// Gehe durch jede Spalte
for (size_t col = 0; col < size; ++col)
{
if (truncateText)
{
truncateToColumnWidth(t_row[col], columnWidths[col], buffer);
}
else
{
splitStringByLength(t_row[col], columnWidths[col], buffer);
}
// Finde die aktuelle Zeile für diese Spalte
char *currentLine = buffer;
int currentLineNum = 0;
char tempBuffer[256] = "";
while (currentLineNum < line)
{
char *newline = strchr(currentLine, '\n');
if (newline == NULL)
{
currentLine = "";
break;
}
currentLine = newline + 1;
currentLineNum++;
}
// Extrahiere die Zeile bis zum nächsten \n oder Ende
int j = 0;
while (currentLine[j] && currentLine[j] != '\n')
{
tempBuffer[j] = currentLine[j];
j++;
}
tempBuffer[j] = '\0';
// Berechne die tatsächliche Anzeigelänge
int printedLength = displayLength(tempBuffer);
// Füge den Inhalt und die fehlenden Leerzeichen hinzu
output += tempBuffer;
int spacesToAdd = columnWidths[col] - printedLength;
for (int k = 0; k < spacesToAdd; k++)
{
output += " ";
}
output += "|";
}
output += "\n";
}
// Füge die Trennlinie hinzu
output += buildLine(line);
return output;
}
void setTruncateText(bool value)
{
truncateText = value;
}
public: // private:
const char **headers;
const int *columnWidths;
size_t size;
bool truncateText = false;
static int displayLength(const char *text)
{
int length = 0;
for (int i = 0; text[i] != '\0'; ++i)
{
if ((text[i] & 0xC0) != 0x80)
{ // Überspringe UTF-8 Fortsetzungsbytes
length++;
}
}
return length;
}
static void safeStringCopy(char *dest, const char *src, size_t bufferSize)
{
if (strlen(src) >= bufferSize)
{
strncpy(dest, src, bufferSize - 1);
dest[bufferSize - 1] = '\0'; // NULL-termination sichergestellt
}
else
{
strcpy(dest, src);
}
}
static void replaceUmlauts(char *text)
{
// UTF-8 Codes für Umlaute (hex): ä(c3 a4) ö(c3 b6) ü(c3 bc) Ä(c3 84) Ö(c3 96) Ü(c3 9c) ß(c3 9f)
struct UmlautPair
{
unsigned char bytes[2]; // UTF-8 bytes
const char *replacement;
};
const UmlautPair pairs[] = {
{{0xc3, 0xa4}, "ae"}, // ä
{{0xc3, 0xb6}, "oe"}, // ö
{{0xc3, 0xbc}, "ue"}, // ü
{{0xc3, 0x84}, "Ae"}, // Ä
{{0xc3, 0x96}, "Oe"}, // Ö
{{0xc3, 0x9c}, "Ue"}, // Ü
{{0xc3, 0x9f}, "ss"} // ß
};
const int numPairs = sizeof(pairs) / sizeof(pairs[0]);
size_t maxOutputLength = strlen(text) * 2 + 1;
char *buffer = (char *)malloc(maxOutputLength);
if (!buffer)
return;
int k = 0; // Position im Ausgabepuffer
int i = 0; // Position im Eingabetext
while (text[i] != '\0')
{
bool replaced = false;
// Prüfe auf UTF-8 Sequenz
if ((unsigned char)text[i] == 0xc3 && text[i + 1] != '\0')
{
for (int j = 0; j < numPairs; ++j)
{
if ((unsigned char)text[i] == pairs[j].bytes[0] &&
(unsigned char)text[i + 1] == pairs[j].bytes[1])
{
// Kopiere Ersetzung
const char *replacement = pairs[j].replacement;
for (int r = 0; replacement[r] != '\0' && k < maxOutputLength - 1; ++r)
{
buffer[k++] = replacement[r];
}
replaced = true;
i += 2; // Überspringe beide UTF-8 Bytes
break;
}
}
}
if (!replaced && k < maxOutputLength - 1)
{
buffer[k++] = text[i++];
}
}
buffer[k] = '\0';
strcpy(text, buffer);
free(buffer);
}
// Neue Version von splitStringByLength
static void splitStringByLength(const char *input, int L, char *output)
{
int len = strlen(input);
int outputIndex = 0;
int currentLength = 0;
for (int i = 0; i < len; ++i)
{
// Kopiere das aktuelle Zeichen zu Ausgabe
unsigned char curr = input[i];
output[outputIndex++] = curr;
// UTF-8-Handling: Überspringe zusätzliche Bytes für ein Multibyte-Zeichen
if ((curr & 0x80) != 0)
{
// Wenn das höchste Bit gesetzt ist, haben wir ein Multibyte-Zeichen
while ((input[i + 1] & 0xC0) == 0x80)
{
output[outputIndex++] = input[++i];
}
}
currentLength++;
// Wenn die maximale Länge erreicht ist und das nächste Zeichen kein newline ist
if (currentLength == L && i + 1 < len && input[i + 1] != '\n')
{
output[outputIndex++] = '\n';
currentLength = 0;
}
}
output[outputIndex] = '\0'; // Beende den String
}
void truncateToColumnWidth(const char *input, int width, char *output)
{
int len = strlen(input);
if (len > width)
{
width = (width > 3) ? width - 3 : width;
strncpy(output, input, width);
strcpy(output + width, "...");
}
else
{
strcpy(output, input);
}
}
size_t calculateMaxLines(char **t_row)
{
size_t maxLines = 0;
for (size_t i = 0; i < size; ++i)
{
const char *text = t_row[i];
size_t textLength = strlen(text);
size_t lines = 1;
for (size_t j = 0; j < textLength; ++j)
{
if (text[j] == '\n')
{
++lines;
}
}
maxLines = max(maxLines, lines);
}
return maxLines;
}
const char *getRowSegment(const char *text, int width, size_t line, char *buffer)
{
size_t textLength = strlen(text);
size_t lineStart = 0;
size_t currentLine = 0;
buffer[0] = '\0';
for (size_t i = 0; i < textLength; ++i)
{
if (currentLine == line)
{
lineStart = i;
break;
}
if (text[i] == '\n' || (i > 0 && (i % width) == 0))
{
++currentLine;
}
}
if (lineStart >= textLength || currentLine != line)
{
return buffer;
}
size_t charCount = 0;
for (size_t i = lineStart; i < textLength && charCount < width; ++i)
{
if (text[i] == '\n')
{
break;
}
buffer[charCount++] = text[i];
}
buffer[charCount] = '\0';
return buffer;
}
String buildLine(char lineChar)
{
String line;
for (size_t i = 0; i < size; ++i)
{
line += '+';
for (int j = 0; j < columnWidths[i]; ++j)
{
line += lineChar;
}
}
line += "+\n";
return line;
}
};
#endif // SERIALTABLE_H
\ No newline at end of file
#include <AUnit.h>
#include "SerialTable.h"
using namespace aunit;
test(SplitStringNoNewlines)
{
char input[] = "This is a test string";
int length = 5;
char expectedOutput[] = "This \nis a \ntest \nstrin\ng";
char actualOutput[256] = {0}; // Ausreichend großer Puffer
SerialTable::splitStringByLength(input, length, actualOutput);
// Überprüfung der Länge der Strings
assertEqual(strlen(expectedOutput), strlen(actualOutput));
/*
// Zusätzliche Debug-Ausgabe, um Hex-Werte zu sehen
for (size_t i = 0; i < strlen(actualOutput); ++i)
{
Serial.print("Expected: ");
Serial.print((int)expectedOutput[i]);
Serial.print(", Actual: ");
Serial.println((int)actualOutput[i]);
}
*/
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 2: Eingabe mit existierenden Zeilenumbrüchen
test(SplitStringWithNewlines)
{
char input[] = "This\nis\na\ntest";
int length = 4;
char expectedOutput[] = "This\nis\na\ntest";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 3: Länge größer als Eingabetext
test(SplitStringLengthGreaterThanText)
{
char input[] = "Short";
int length = 10;
char expectedOutput[] = "Short";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 4: Genau passende Länge
test(SplitStringExactLength)
{
char input[] = "Lengthy";
int length = 7;
char expectedOutput[] = "Lengthy";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 5: Länge von 1
test(SplitStringLengthOfOne)
{
char input[] = "One";
int length = 1;
char expectedOutput[] = "O\nn\ne";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Einzelner Testfall 6: Leerer Eingabestring
test(SplitStringEmptyInput)
{
char input[] = "";
int length = 5;
char expectedOutput[] = "";
char actualOutput[256] = {0};
SerialTable::splitStringByLength(input, length, actualOutput);
assertEqual(String(expectedOutput), String(actualOutput));
}
// Erstelle eine Hilfsfunktion für replaceUmlauts-Tests
test(replaceUmlautsTest)
{
char text1[] = "Köln";
SerialTable::replaceUmlauts(text1);
assertEqual("Koeln", text1);
char text2[] = "München";
SerialTable::replaceUmlauts(text2);
assertEqual("Muenchen", text2);
char text3[] = "Straße";
SerialTable::replaceUmlauts(text3);
assertEqual("Strasse", text3);
}
// Erstelle eine Hilfsfunktion für truncateTextTest
test(truncateTextTest)
{
char buffer[20];
SerialTable table(nullptr, nullptr, 0);
// Fall: Text passt in die Spaltenbreite
strcpy(buffer, "Hello");
table.truncateToColumnWidth(buffer, 10, buffer);
assertEqual("Hello", buffer);
// Fall: Text wird abgeschnitten
strcpy(buffer, "HelloWorld!");
table.truncateToColumnWidth(buffer, 5, buffer);
assertEqual("He...", buffer);
}
test(buildHeaderTest1)
{
// Definiere header mit char*-Zeigern
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
// Verwende buildHeader, um den Header-String zu erhalten
String header = table.buildHeader();
// Gib den Header über Serial aus
Serial.print(header);
Serial.flush();
// Erwartete Ausgabe des Headers
String expectedHeader =
"+----------+-----+----------+\n"
"|Name |Age |City |\n"
"+==========+=====+==========+\n";
// Vergleiche den erzeugten Header mit dem erwarteten Header
assertEqual(expectedHeader, header);
}
test(buildHeaderTest2)
{
// Definiere header mit char*-Zeigern
const char *headers[] = {"NameName Name", "Age Age Age", "CityCityCity"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
// Verwende buildHeader, um den Header-String zu erhalten
String header = table.buildHeader();
// Gib den Header über Serial aus
Serial.print(header);
Serial.flush();
// Erwartete Ausgabe des Headers
String expectedHeader =
"+----------+-----+----------+\n"
"|NameName N|Age A|CityCityCi|\n"
"|ame |ge Ag|ty |\n"
"| |e | |\n"
"+==========+=====+==========+\n";
// Vergleiche den erzeugten Header mit dem erwarteten Header
assertEqual(expectedHeader, header);
}
test(buildHeaderTest3)
{
// Definiere header mit char*-Zeigern
const char *headers[] = {"ä123", "ö123", "ü123"};
const int columnWidths[] = {4, 4, 4};
SerialTable table(headers, columnWidths, 3);
// Verwende buildHeader, um den Header-String zu erhalten
String header = table.buildHeader();
// Gib den Header über Serial aus
Serial.print(header);
Serial.flush();
// Erwartete Ausgabe des Headers
String expectedHeader =
"+----+----+----+\n"
"|ä123|ö123|ü123|\n"
"+====+====+====+\n";
// Vergleiche den erzeugten Header mit dem erwarteten Header
assertEqual(expectedHeader, header);
}
test(printHeaderTest)
{
// Verwende char*-Array statt String-Array
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
table.printHeader();
Serial.flush();
// Placeholder assertion, Verwendung eines Serial Monitor Tools empfohlen
assertTrue(true);
}
test(buildRowTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"Alice", "30", "Wonderland"};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"|Alice |30 |Wonderland|\n"
"+----------+-----+----------+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(printRowWithMultipleLinesTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 5};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"Alice", "30", "Wonderland"};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"|Alice |30 |Wonde|\n"
"| | |rland|\n"
"+----------+-----+-----+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(printRowWithLongTextTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"A very long name", "12345", "A very long city name"};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"|A very lon|12345|A very lon|\n"
"|g name | |g city nam|\n"
"| | |e |\n"
"+----------+-----+----------+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(printEmptyRowTest)
{
const char *headers[] = {"Name", "Age", "City"};
const int columnWidths[] = {10, 5, 10};
SerialTable table(headers, columnWidths, 3);
char *rows[] = {"", "", ""};
// Verwende buildRow, um den Zeilen-String zu bekommen
String rowOutput = table.buildRow(rows);
// Gib die Zeile über Serial aus
Serial.print(rowOutput);
Serial.flush();
// Erwartete Ausgabe der Zeile
String expectedRowOutput =
"| | | |\n"
"+----------+-----+----------+\n";
// Vergleiche den generierten Zeilen-String mit dem erwarteten Zeilen-String
assertEqual(expectedRowOutput, rowOutput);
}
test(DisplayLengthBasic) {
assertEqual(5, SerialTable::displayLength("Hello"));
}
test(DisplayLengthWithSpace) {
assertEqual(11, SerialTable::displayLength("Hello World"));
}
test(DisplayLengthWithUmlauts) {
// "Müller" in UTF-8 hat eine Länge von 6 Zeichen (ä zählt als 1 Zeichen)
assertEqual(6, SerialTable::displayLength("Müller"));
}
test(DisplayLengthOnlyUmlauts) {
// "äöü" in UTF-8 sollten jeweils als ein Zeichen zählen
assertEqual(3, SerialTable::displayLength("äöü"));
}
test(DisplayLengthUTF8Emojis) {
// "😀😃😄" Emojis können mehrere Bytes haben, prüfen ob jedes nur als ein Zeichen gezählt wird
assertEqual(3, SerialTable::displayLength("😀😃😄"));
}
test(DisplayLengthWithNewline) {
// "Hello\nWorld" hat eine Länge von 11 Zeichen, da \n als einzelnes Zeichen zählt
assertEqual(11, SerialTable::displayLength("Hello\nWorld"));
}
test(DisplayLengthEmptyString) {
// Ein leerer String sollte eine Länge von 0 haben
assertEqual(0, SerialTable::displayLength(""));
}
test(DisplayLengthSpaces) {
// " " hat eine Länge von 3 Leerzeichen
assertEqual(3, SerialTable::displayLength(" "));
}
+---------------+--------------------+----------+
|Header 1 |Header 2 |Header 3 |
+===============+====================+==========+
|Text | |Text |
+---------------+--------------------+----------+
|Text |Text | |
+---------------+--------------------+----------+
| |Text |Text1 |
|Text | |Text2 |
+---------------+--------------------+----------+
|Alice |30 |Wonde|
| | |rland|
+----------+-----+-----+
|Alice |30 |Wonderland|
+----------+-----+-----+
|Alice |30 |Wonde|
| | |rland|
+----------+-----+-----+
|Alice |30 |Wonde
rland|
+----------+-----+-----+
#include <Arduino.h>
#include "UnitTests.h"
#include "SerialTable.h"
void setup()
{
// Initialisieren der seriellen Verbindung
Serial.begin(115200);
// Definieren der Kopfzeilen und Spaltenbreiten für 8 Spalten
const char *headers[] = {"Vorname", "Nachname", "Alter", "Stadt", "Beruf", "Unternehmen", "Hobby", "Bemerkung"};
int columnWidths[] = {10, 15, 5, 10, 10, 15, 10, 20};
SerialTable table(headers, columnWidths, 8);
table.printHeader();
// Erstellen von 20 Zeilen mit unterschiedlichen Einträgen
char *rows[20][8] = {
{"Alice", "Wonderland", "30", "Köln", "Ingenieur", "FirmaX", "Schwimmen", "Keine"},
{"Bob", "Builder\nJr", "35", "Berlin", "Architekt", "Architektur AG", "Bauen", "Sehr erfahren"},
{"Charlie", "Brown", "28", "Hamburg", "Designer", "Die Design", "Zeichnen", "Mag Karikaturen"},
{"David", "Tennant", "40", "München", "Schauspieler", "Freiberufler", "Lesen", "Doktor gewesen"},
{"Emma", "Watson", "33", "Frankfurt", "Schauspielerin", "Independent", "Yoga", "Bekannt aus Filmen"},
{"Frank", "Herbert", "45", "Stuttgart", "Autor", "Ein Verlag", "Schreiben", "Bücher geschrieben"},
{"Grace", "Hopper", "50", "Berlin", "Programmiererin", "Tech Corp", "Informatik", "Pionierin"},
{"Hugo", "Strange", "60", "Leipzig", "Psychiater", "Gesundheits GmbH", "Philosophie", "Ruhestand"},
{"Irene", "Adler", "29", "Dresden", "Detektivin", "Privat", "Abenteuer", "Scharfsinnig"},
{"John", "Doe", "49", "Bremen", "Buchhalter", "Kontorechner", "Radfahren", "Gewissenhaft"},
{"Klara", "Kühn", "39", "Hannover", "Lehrerin", "Schule ABC", "Lesen", "Einfühlsam"},
{"Lenny", "Small", "25", "Koblenz", "Musiker", "Orchester", "Gitarre", "Kreativ"},
{"Mona", "Lisa", "33", "Siegen", "Malerin", "Kunsthaus", "Kunst", "Geheimnisvoll"},
{"Nina", "Simone", "30", "Essen", "Sängerin", "Soul Musik", "Musik", "Talentiert"},
{"Oliver", "Twist", "19", "Potsdam", "Student", "Uni XY", "Fußball", "Engagiert"},
{"Pam", "Beesly", "32", "Wuppertal", "Sekretärin", "Dunder Mifflin", "Malen", "Freundlich"},
{"Quinn", "Fabray", "26", "Magdeburg", "Designer", "Agentur XYZ", "Tanzen", "Kreativ"},
{"Ron", "Swanson", "55", "Bielefeld", "Verwalter", "Rathaus", "Holzarbeiten", "Direkt"},
{"Sophia", "Loren", "70", "Osnabrück", "Schauspielerin", "Independent", "Kochen", "Ikonisch"},
{"Tom", "Hanson", "36", "Regensburg", "Polizist", "Polizei", "Jagen", "Schützend"},
};
// Drucke die Zeilen
for (int i = 0; i < 20; ++i)
{
table.printRow(rows[i]);
}
}
void loop()
{
//TestRunner::run();
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment