In C werden die Trennzeichen in so einem String gerne durch Nullbytes ersetzt und ein Pointer auf den Anfang von jedem Substring gesetzt. Das spart Speicherplatz und Zeit fürs Kopieren.
Das wird auch nicht kleiner
Erstmal musst Du feststellen, ob in Deinem String überhaupt ein Trennzeichen drin ist.
Dann musst Du feststellen, ob das erste und das letzte Trennzeichen eine unterschiedliche Position hat.
Dann gehört eine Prüfung rein, ob die Anzahl der Trennzeichen +1 in Dein Array passt.
Und erst dann gehört das geteilt.
Wenn Du mit CharArray und nicht mit String arbeitest, ginge strtok um die Zeichenkette aufzulösen.
Damit könntest dann auch gleich eine Zuordnung zu einer Variablen bauen.
Wie ich so einen Puffer zerlege, habe ich hier gezeigt - im ersten Sketch
Mit strtok. Ich habe in meiner Arduino Anfangszeit mal eine RGB-LED über eine Eingabezeile vom seriellen Monitor gesteuert. Evtl. hilft Dir das beim Verständnis.
der Ansatz von @agmue hat mir gefallen. Vieleicht will man ja die Werte einzeln haben um damit z.B. weiterzurechnen.
Wenn es immer Wertpaare sind (getrennt mit : und ; ) dann kann man das auch entsprechend mit strtok einlesen. Es würde sich dann eine Struktur anbieten: Jedes Paar besteht aus einem Ort und dem Wert.
// Convert an Arduino String into an array
// https://forum.arduino.cc/t/string-zerlegen-und-in-array-aufteilen/955678/9
// by noiasca
String myString = "Außen:2.9;Innen:22.6;Dachboden:15.0;Keller:17.3";
constexpr byte size = 20; // Größe für den Bezeichner
struct Wetterdaten
{
char ort[size]; // von welchem Sensor kommen die Daten
float value = 0; // der Wert
};
Wetterdaten wetterdaten[4]; // wir benötigen für das Beispiel 4 Instanzen von Wetterdaten
void string2array() // konvertiert einen Arduino String in ein Array
{
char zeile[80]; // einen Buffer für die ganze Zeile zur Verfügung stellen
snprintf( zeile, sizeof(zeile), "%s", myString.c_str() ); // String zu char buffer machen
char val[size]; // einen Buffer für die Werte-Konvertierung
snprintf(wetterdaten[0].ort, size, "%s", strtok(zeile, ":;") ); // zerteilen beginnen
snprintf(val, size, "%s", strtok(NULL, ":;") ); // Wert in Buffer einlesen
wetterdaten[0].value = atof(val); // buffer in float konvertieren
for (size_t i = 1; i< sizeof(wetterdaten)/sizeof(wetterdaten[0]); i++) // die restlichen 3 Wertpaare einlesen
{
snprintf(wetterdaten[i].ort, size, "%s", strtok(NULL, ":;") );
snprintf(val, size, "%s", strtok(NULL, ":;") );
wetterdaten[i].value = atof(val);
}
}
void ausgabe() // Einfache Ausgabe aller aktuell gespeicherten Werte
{
for (auto &i : wetterdaten) // durch das ganze struct array durchgehe
{
Serial.print(i.ort);
Serial.print(" ");
Serial.println(i.value);
}
}
void berechnen() // eine Berechnung mit den gespeicherten Werten vornehmen
{
float unterschied = wetterdaten[0].value - wetterdaten[1].value;
Serial.print(F("Der Temperaturunterschied zwischen "));
Serial.print(wetterdaten[0].ort); // Zugriff auf das erste Element im Array
Serial.print(F(" und "));
Serial.print(wetterdaten[1].ort); // Zugriff auf das zweite Element im Array
Serial.print(F(" beträgt "));
Serial.print(unterschied, 1); // Float Ausgabe mit einer Nachkommastelle
}
void setup()
{
Serial.begin(115200);
Serial.println(F("Start..."));
string2array(); // konvertieren
ausgabe(); // alles ausgeben
berechnen(); // etwas mit den Werten tun
}
void loop() {}
soll ausgeben
Start...
Außen 2.90
Innen 22.60
Dachboden 15.00
Keller 17.30
Der Temperaturunterschied zwischen Außen und Innen beträgt -19.7
Ist es sinnvoll, Programme ausschließlich auf einem externen Server wie wokwi.com zu zeigen? Der könnte irgendwann verschwunden sein, womit dieser Beitrag unverständlich würde.
Daher eine Kopie:
String myString = "Außen:2.9;Innen:22.6;Dachboden:15.0;Keller:17.3";
constexpr byte size = 20; // Größe für den Bezeichner
struct Wetterdaten
{
char ort[size]; // von welchem Sensor kommen die Daten
float value = 0; // der Wert
};
Wetterdaten wetterdaten[4]; // wir benötigen für das Beispiel 4 Instanzen von Wetterdaten
void string2array() // konvertiert einen Arduino String in ein Array
{
char zeile[80]; // einen Buffer für die ganze Zeile zur Verfügung stellen
snprintf( zeile, sizeof(zeile), "%s", myString.c_str() ); // String zu char buffer machen
char val[size]; // einen Buffer für die Werte-Konvertierung
snprintf(wetterdaten[0].ort, size, "%s", strtok(zeile, ":;") ); // zerteilen beginnen
snprintf(val, size, "%s", strtok(NULL, ":;") ); // Wert in Buffer einlesen
wetterdaten[0].value = atof(val); // buffer in float konvertieren
for (size_t i = 1; i< sizeof(wetterdaten)/sizeof(wetterdaten[0]); i++) // die restlichen 3 Wertpaare einlesen
{
snprintf(wetterdaten[i].ort, size, "%s", strtok(NULL, ":;") );
snprintf(val, size, "%s", strtok(NULL, ":;") );
wetterdaten[i].value = atof(val);
}
}
void ausgabe() // Einfache Ausgabe aller aktuell gespeicherten Werte
{
for (auto &i : wetterdaten) // durch das ganze struct array durchgehe
{
Serial.print(i.ort);
Serial.print(" ");
Serial.println(i.value);
}
}
void berechnen() // eine Berechnung mit den gespeicherten Werten vornehmen
{
float unterschied = wetterdaten[0].value - wetterdaten[1].value;
Serial.print(F("Der Temperaturunterschied zwischen "));
Serial.print(wetterdaten[0].ort); // Zugriff auf das erste Element im Array
Serial.print(F(" und "));
Serial.print(wetterdaten[1].ort); // Zugriff auf das zweite Element im Array
Serial.print(F(" beträgt "));
Serial.print(unterschied, 1); // Float Ausgabe mit einer Nachkommastelle
}
void setup()
{
Serial.begin(115200);
Serial.println(F("Start..."));
string2array(); // konvertieren
ausgabe(); // alles ausgeben
berechnen(); // etwas mit den Werten tun
}
void loop() {}
Du sprichst mir aus der Seele. Bisher haben wir immer Wert darauf gelegt, dass der Code direkt hier im Forum liegt. Das sollten wir beibehalten bzw. wieder verstärkt durchsetzen.
Code auf anderen Servern sollten wir ignorieren.
Mir ist das nicht zu absolut, sondern zu anstrengend.
Ich ignoriere, solchen Code, noch nicht einmal.
Beispiel:
Angenommen sscanf() wäre ein probates Mittel solche Probleme zu lösen. Dann scheitert der Simulator schon daran, dass man Float darin nicht aktivieren kann, oder es darin schon aktiviert ist.
Bei mir sähe das so aus, wenn ich die Anzahl der Datensätze im String nicht sicher vorhersagen kann:
const int MaxString = 5;
String strings[MaxString];
String Teststring = "Aussen:2.9;Innen:22.6;Dachboden:15.0;Keller:17.3;Aussen:3.9;Innen:23.6;Dachboden:16.0;Keller:18.3";
size_t Split(String& input, char Sep) {
int count = 0;
int p = input.indexOf(Sep);
while (p >= 0 && count < MaxString-1) {
strings[count] = input.substring(0,p);
count++;
input = input.substring(p+1);
p = input.indexOf(Sep);
}
if (input.length() > 0) {
if (input.indexOf(Sep) < 0) {
strings[count] = input;
count++;
input = "";
}
}
return count;
}
void PrintStrings(int No) {
for (int i = 0; i < No; i++) {
Serial.println(strings[i]);
}
}
void setup(){
Serial.begin(115200);
Serial.println("... Split ...");
while (Teststring.length() > 0){
int w = Split(Teststring,';');
PrintStrings(w);
}
}
void loop(){}
Über const int MaxString = ... kann man dabei den Speicherbedarf regulieren; je mehr hier möglich ist, um so seltener muss die Split() Funktion wiederholt werden (siehe while-Schleife im setup() ).
Och.....
In Sachen \0 gibts da, glaube ich, wenig Unterschied, zwischen C und C++.
Wobei uns Arduinos sowieso C einigermaßen fern ist.
Denn selbst Serial ist klipp und klar und ausschließlich C++
Die << machen den Braten wohl nicht fett, außer, dass man dann auch moderne C++ Bücher besser zu lesen versteht.