Forum: Mikrocontroller und Digitale Elektronik Strings kopieren in "Arduinoumgebung" mit strncpy


von Matthias S. (mat-sche)


Lesenswert?

Liebes Forum,

sitze hier schon seit tagen drann und komm nicht weiter.
Ich habe einen String : [_A,index,2.80,182,]E6B1
Ich benötige in einzellnen Variablen: ,index,2.80,182,

Das ganze läuft auf einem ESP8266 und das Programm schreibe ich in der 
Arduino IDE.
Der Code:
1
// # Datenarray ([_A/temp/,Index,246,]53ED) ohne CRC-Checksumme extrahieren (53ED)
2
     token = strrchr(chararray_ser,']');                                                      
3
     komma[1] = token +1 - chararray_ser;                                                                                                  
4
     strncpy(Daten_1,chararray_ser,komma[1]);                                                  
5
     Daten_1[komma[1]] = '\0';
6
                                                                    
7
     // # CRC-16/XMODEM => CRC berechnen
8
     crc_1 = crc16((uint8_t *) Daten_1, strlen(Daten_1), 0x1021, 0, 0, false, false);              
9
                    
10
     // # Datenarray CRC-Checksumme extrahieren  
11
     komma[2] = str_len - komma [1];
12
     Serial.print("komma[2]= "); Serial.println(komma[2]);
13
     strncpy(Daten_1,chararray_ser + komma[1],komma[2]);                                    
14
     Daten_1[komma[1]] = '\0';                                                              
15
     long test = strtol(Daten_1, NULL, 16);
16
    
17
    // # Checksummenvergleich aus Datenarray und berechnenten CRC
18
     if(test == crc_1)
19
     {
20
      Serial.print("crc Ver-Gleich == gleich");
21
     }
22
       else
23
     {  
24
      Serial.println("crc Ver-Gleich == ungleich");
25
     }
26
27
     // # Komma Stellen suchen, Platz im chararray wird gesucht    
28
     token=strchr(chararray_ser,',');                                                    
29
     while (token!=NULL)                                                                  
30
     {
31
       komma[count_[0]]= token-chararray_ser+1;                                            
32
       token=strchr(token+1,',');                                                          
33
       count_[0]++ ;                                                                        
34
     }
35
     // # Anzahl der Zeichen zwischen den äußeren Kommatas berechnen
36
     anzahl = komma[count_[0]-1] - komma[0];
37
    
38
     // # Daten zwischen den Kommas in Daten_1 kopieren
39
     strncpy(Daten_1,chararray_ser + komma[0],anzahl);
40
     Daten_1[komma[count_[0]-1]] = '\0';    
41
     Serial.print("  Daten_1 "); Serial.println(Daten_1);
42
43
44
//Serial.println( "" ); 
45
     //Serial.println( "Zerlege chararray_ser _,_" );
46
     //Serial.println( "" ); 
47
     char *ptr, *savePtr, *p, *saveP;
48
    
49
     ptr = strtok_r(Daten_1,",",&savePtr);
50
     Serial.print("1. strtok ");Serial.println(ptr); 
51
     while(ptr != NULL) 
52
    {
53
     count_[0]++;
54
     p = strtok_r(ptr,",",&saveP);
55
     
56
     Serial.print("count[0]- ");Serial.print(count_[0]);Serial.print("  1nd-p ");Serial.println(p);     
57
     ptr = strtok_r(NULL,",",&savePtr);
58
    }
Grundsätzlich funktioniert der Code, habe jedoch ein Fehler drinnen, den 
ich mir nicht erklären kann.
1
     strncpy(Daten_1,chararray_ser + komma[0],anzahl);
2
     Daten_1[komma[count_[0]-1]] = '\0';    
3
     Serial.print("Daten_1= "); Serial.println(Daten_1);
Hier wird nicht richtig die gewünschten Daten  in "Daten_1" kopiert.
Bsp.
String vom Uart empfangen:
1
[_A,index,2.80,182,]E6B1
String nach dem kopieren:
1
Daten_1= index,2.80,182,182,
2
Warum wird die 182, doppelt in die Variable Daten_1 kopiert?
Hat jemand dazu eine Idee?

Vielen DAnk MAT

von PittyJ (Gast)


Lesenswert?

Ich habe selten so einen Sch.. mit den alten Stringfunktionen gesehen.

Arduino ist C++. Da geht auch std::string mit seinen ganzen 
Hilfsfunktionen. Da braucht ein Anfänger nicht aufpassen, ob die 
Array-Länge reicht und ob ein Pointer noch gültig ist.

Dann pack das ganze in Funktionen, die z.B. jeweils bis zum Komma lesen, 
oder das in Unterstrings aufteilen. Für so etwas hat man ja die 
Funktionen erschaffen.

Mein Vorschlag: lösch den ganzen Krams, und fang noch einmal an.

von Cyblord -. (cyblord)


Lesenswert?

PittyJ schrieb:
> Mein Vorschlag: lösch den ganzen Krams, und fang noch einmal an.

Mein Vorschlag: Er soll Gärtnern und nicht programmieren. So ein Code 
zeigt deutlich dass ein komplett falsches Mindset für diese Tätigkeit 
vorliegt.

von Matthias S. (mat-sche)


Lesenswert?

PittyJ schrieb:
> Mein Vorschlag: lösch den ganzen Krams, und fang noch einmal an.

Na dann mal los! :)

Hatte vergessen, dass ich noch blutiger Anfänger bin!
Ich wollte mich ersteinmal da durcharbeiten und dann mit den Funktionen 
rantrauen.

PittyJ schrieb:
> std::string
Davon hab ich schon was gehört....

Cyblord -. schrieb:
> Mein Vorschlag: Er soll Gärtnern und nicht programmieren. So ein Code
> zeigt deutlich dass ein komplett falsches Mindset für diese Tätigkeit
> vorliegt.

Ohhh da war Dein Vorredner etwas Einfühlsamer!
... und nen schönen Garte habe ich, dafür soll es was werden, mit dem 
Programm ;)
(zum Glück hab ich ein dickes Fell und kenn hier den rauhen Ton! Zum 
Glück sind ja nicht alle wie Ihr :) )
MAT

von EAF (Gast)


Lesenswert?

Matthias S. schrieb:
> Ohhh da war Dein Vorredner etwas Einfühlsamer!

Einige haben die soziale Kompetenz einer Bordsteinkante.

von Bär (Gast)


Lesenswert?

> Ohhh da war Dein Vorredner etwas Einfühlsamer!
> ... und nen schönen Garte habe ich, dafür soll es was werden, mit dem
> Programm ;)
> (zum Glück hab ich ein dickes Fell und kenn hier den rauhen Ton! Zum
> Glück sind ja nicht alle wie Ihr :) )
> MAT


Die perfekte Antwort! Gefällt mir!

von Arno (Gast)


Lesenswert?

Matthias S. schrieb:
> Hat jemand dazu eine Idee?

Vermutlich (schließe ich aus deinen komma-Berechnungen) hast du den 
Unterschied zwischen Zeigern, Referenzen, dem Speicherbereich, auf den 
Zeiger oder Referenzen zeigen sowie den Datentypen size_t und int nicht 
verstanden.

Genauer kann ich dir das nicht sagen, weil ich die von dir verwendeten 
Datentypen nicht kenne, du zeigst sie uns ja nicht.

MfG, Arno

von DaMusstDuDurch (Gast)


Lesenswert?

Hallo Matthias,

schön, das du den Weg hierher gefunden hast.

Leider wirst du bald feststellen, das sich in diesem Forum einige Typen 
versammeln, die ein soziales und geistiges Handicap haben. Sie befinden 
sich im Stadium unheilbar.

Ich bin sicher, dass dir mittelfristig geholfen wird.

Gruß DaMusstDuDurch

von hellseher (Gast)


Lesenswert?

DaMusstDuDurch schrieb:
> Ich bin sicher, dass dir mittelfristig geholfen wird.

Bei solch einem Code-Chaos sehr mittelfristig.

von Matthias S. (mat-sche)


Lesenswert?

Arno schrieb:
> Genauer kann ich dir das nicht sagen, weil ich die von dir verwendeten
> Datentypen nicht kenne, du zeigst sie uns ja nicht.

Da hast Du recht, das war mein Versäumnis!
1
     char * token;                                                                      // token Bedeutung = Zeichen 
2
     int count_[4] = {0,0,0,0};
3
     //char Tiken[11];
4
     byte komma[10];
5
     byte anzahl;
6
     char Daten_1[40];                                                                   // Zwischenpuffer für das extrahierte Chararray ohne crc16-Daten
7
    char Daten_2 [40];                                                                  // Zwischenpuffer für Zwischenspeicherung Chararray (z.Bsp.: crc16) 
8
     uint16_t crc_1;

Also zurück zum Thema, wenn ich besser wüste, würde ich hier nicht 
fragen!
An die "Überflieger" hier im Forum, ich habe diesen String, der über 
UART reinkommt: [_A,index,2.80,182,]E6B1. Ich benötige die Werte
1. "index"
2. 2.80
3. 182
4. E6B1
wie würdet Ihr vorgehen, um an diese Variablen ranzukommen?

von EAF (Gast)


Lesenswert?

Matthias S. schrieb:
> Hatte vergessen, dass ich noch blutiger Anfänger bin!
Das sehen wir!
Musst du also nicht sagen.
(Regen ist nass)

Matthias S. schrieb:
> Ich wollte mich ersteinmal da durcharbeiten und dann mit den Funktionen
> rantrauen.

Was du willst, scheint mit zu sein, Daten analysieren/interpretieren, um 
dann irgendwas damit anzustellen.

Ich fasse das erste halbe Dutzend der notwendigen Schritte, auf dem Weg, 
mal als "Parser" zusammen.
Der Parserbau ist eine wunderbare Gelegenheit, um sich mit endlichen 
Automaten zu beschäftigen.


Schritt1:
Erstmal benötigt man eine glasklare Definition der eintrudelnden Daten.
Was ist Was!

Hier ist schon der erste Konflikt.

Matthias S. schrieb:
> [_A,index,2.80,182,]E6B1

Matthias S. schrieb:
> ([_A/temp/,Index,246,]53ED

Einmal 3, einmal 4, in den eckigen Klammern.
Das wirft die Frage auf: Wie viele mag es da wohl geben?
96 Tausend?

von Matthias S. (mat-sche)


Lesenswert?

EAF schrieb:
> Was du willst, scheint mit zu sein, Daten analysieren/interpretieren, um
> dann irgendwas damit anzustellen.

Das ist richtig! Ich habe auf der einen Seite einen ATmega2560 mit einem 
Display 128x240. Auf dem werden Daten generiert, die über Uart auf einen 
ESP geschickt werden sollen. Diese möchte ich dann auf einer Webseite 
darstellen.

EAF schrieb:
> Matthias S. schrieb:
>> [_A,index,2.80,182,]E6B1
>
> Matthias S. schrieb:
>> ([_A/temp/,Index,246,]53ED

Das sind unterschiedliche Ideen, diese Daten zusammen zustellen. Von 
INteresse wäre:
- "index" (dies soll die Dateninfo für die Art/Bestimmung der Daten 
sein; es sollen später noch weiter hinzukommen)
=> das wäre ein String oder Chararray (was wäre denn besser??)
- 2.80.... max. 10 Datensätze
=> das wären Byts, Single oder auch Chararrays
- 53ED = crc-16 Checksumme, die vom Sendesystem über die Daten in den 
Klammern [...] errechnet wurde
=> das wäre eine Hex Int

Soviel zu den Daten.

von EAF (Gast)


Lesenswert?

Matthias S. schrieb:
> Das sind unterschiedliche Ideen, diese Daten zusammen zustellen.
So so...
Das Protokoll ist nicht ausgereift!

Dabei ist die Reihenfolge doch offensichtlich!
Ohne fertiges Protokoll, keinen Parser.

Dann hier ein Tipp:
Verwende den CmdMessenger.
Evtl, etwas gewöhungsbedürftig, aber der Parser ist schon fertig.

von Matthias S. (mat-sche)


Lesenswert?

EAF schrieb:
> Das Protokoll ist nicht ausgereift!
Das wird so sein, weil ich es mir im Moment es so vorstelle, dass es so 
laufen kann.
Dann sollte ich ersteinmal mich schlau machen, wie ein Protokoll 
aufgebaut, "design" werden sollte.

EAF schrieb:
> Dabei ist die Reihenfolge doch offensichtlich!
Wie meinst Du das?

EAF schrieb:
> Verwende den CmdMessenger.

Das ist doch schon einmal ne Richtung! Danke!

von EAF (Gast)


Lesenswert?

Matthias S. schrieb:
> EAF schrieb:
>> Dabei ist die Reihenfolge doch offensichtlich!
> Wie meinst Du das?

Ein Parser ist hochspezialisiert. In der Regel.
Die kleinste Änderung an den "Voraussetzungen" befördert ihn und alle 
vorhergehende Arbeit in die Tonne.

Von daher: Erst das Protokoll, dann der Parser.

von Matthias S. (mat-sche)


Lesenswert?

EAF schrieb:
> on daher: Erst das Protokoll, dann der Parser.

OK! Dann brauche ich  noch einwenig Hintergrundwissen.
Von meinem Sender möchte ich schicken:
1. Zeichenketten
2. byte-Variablen
3. Intergerwerte
4. Hexadezimalewerte
5.....

Mein Sendesystem habe ich mit Bascom programmiert und stell mich etwas 
schwer mit c++.
In welcher Form bereite ich meine Daten auf, dass diese leicht zu 
versenden sind? Also verschicke ich nur Strings, die ich am Ausgang und 
dann wieder auf der Empfängerseite zurück gewandelt werden müssen?

von Frank G. (frank_g53)


Lesenswert?

Von meinem Sender möchte ich schicken:
1. Zeichenketten
2. byte-Variablen
3. Intergerwerte
4. Hexadezimalewerte

Matthias S. schrieb:
> Also verschicke ich nur Strings, die ich am Ausgang und
> dann wieder auf der Empfängerseite zurück gewandelt werden müssen?

Matthias S. schrieb:
> Mein Sendesystem habe ich mit Bascom programmiert

Du musst dir ein Protokoll in der Art aufbauen:
Rohdaten senden "#S(string)#B(byte)#I(integerwert)#H(hexdezimal)"

Empfänger sollte nun die ankommenden Zeichen einordnen können:
wenn #S dann die nächsten Zeichen bis zum nächsten # ein String
wenn #B dann die nächsten Zeichen bis zum nächsten # ein Byte
...

von Cyblord -. (cyblord)


Lesenswert?

Matthias S. schrieb:
> In welcher Form bereite ich meine Daten auf, dass diese leicht zu
> versenden sind? Also verschicke ich nur Strings, die ich am Ausgang und
> dann wieder auf der Empfängerseite zurück gewandelt werden müssen?

Am leichtesten für Computer sind immer Rohdaten vulgo Binärdaten. D.h. 
keine Strings.

Du kannst den statischen Ansatz wählen: Feste Pakete mit fester 
Struktur. Da weißt du genau an welcher Stelle welcher Datentyp steht und 
wie lang der ist.
Das kann man dann sogar direkt mit einer C-Struktur abbilden.

Oder den dynamischen: z.B. TLV (Type-Length-Value). Da kannst du 
beliebige Daten rein tun, musst aber jedes Datum mit Meta-Daten 
anreichern. Nämlich Typ und Länge.

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Cyblord -. schrieb:
> Am leichtesten für Computer sind immer Rohdaten vulgo Binärdaten. D.h.
> keine Strings.

Das geht solange gut, bis Systeme mit verschiedener Endianess 
aufeinander treffen.
Dann steigt der Aufwand.

von Dirk B. (dirkb2)


Lesenswert?

Matthias S. schrieb:
> OK! Dann brauche ich  noch einwenig Hintergrundwissen.
> Von meinem Sender möchte ich schicken:
> 1. Zeichenketten
> 2. byte-Variablen
> 3. Intergerwerte
> 4. Hexadezimalewerte
> 5.....

Sendet der einfach so drauf los, oder gibt es vorher eine Anfrage?

Die Werte stehen doch für irgendwas. Kannst denen nicht Namen/Tags 
geben?

von Matthias S. (mat-sche)


Lesenswert?

Dirk B. schrieb:
> Sendet der einfach so drauf los, oder gibt es vorher eine Anfrage?

Das mache ich ja schon. Ich weiss was ich an welcher Stelle sende bzw. 
empfange. Im Eingangspost zeigte ich meine Weise auf, wie und was ich 
mit den Datenstring mache und dann wurden meine wackligen Gehversuche 
"auseinander" genommen.
Im Grunde genommen bekomme ich schon meine Daten, nur wird mir 
unerklärlich am Schluss eine Variable doppelt kopiert.
 Hmmm, mache jetzt dai dai und morgen geht's weiter.
Gute Nacht.

von Arno (Gast)


Lesenswert?

Matthias S. schrieb:
> Arno schrieb:
>> Genauer kann ich dir das nicht sagen, weil ich die von dir verwendeten
>> Datentypen nicht kenne, du zeigst sie uns ja nicht.
>
> Da hast Du recht, das war mein Versäumnis!
>
>
1
>      char * token; 
2
> // token Bedeutung = Zeichen
3
>      int count_[4] = {0,0,0,0};
4
>      //char Tiken[11];
5
>      byte komma[10];
6
>      byte anzahl;
7
>      char Daten_1[40]; 
8
> // Zwischenpuffer für das extrahierte Chararray ohne crc16-Daten
9
>     char Daten_2 [40]; 
10
> // Zwischenpuffer für Zwischenspeicherung Chararray (z.Bsp.: crc16)
11
>      uint16_t crc_1;
12
>
>

Damit ist zwar immer noch sehr konfus, vor allem mit Variablen-Namen wie 
anzahl, komma, count_ und davon noch jeweils Arrays, aber so ein 
bisschen verstehe ich, was da passieren soll.

Verdacht: Du kopierst anzahl Zeichen nach Daten1[], setzt dann aber 
nicht das Zeichen an Position anzahl auf \0, sondern das Zeichen an 
Position komma[count_[0] -1 ]. Und da vorher schon was in Daten1[] 
drinstand, bleibt das da.

Tipp: Nach jedem Schritt alle Zwischenergebnisse (mit Zeilennummer) 
ausgeben oder im Debugger anzeigen, dann solltest du selbst darauf 
kommen.

Und mittelfristig, um solche Fehler nicht zu wiederholen: Viel, viel 
weniger Chaos produzieren ;)

Du kannst zum Beispiel char_ser (oder eine Kopie davon) verändern, statt 
immer wieder komma[n] = strlen(...) - komma[n-1] zu rechnen.  Die 
String-Funktionen haben auch Rückgabewerte, die man nutzen kann und 
sollte. Es ist auch Quatsch, n+1 Zeichen zu kopieren, um dann das 
Zeichen an Stelle n auf \0 zu setzen - das spart dir vermutlich ein paar 
magic +1 und -1. Und dann kann es gut sein, dass du die ganze 
Substring-Kopiererei viel besser in eine Funktion kapseln kannst, die du 
mehrfach aufrufst. Wenn es nicht eh schon eine Standard-Funktion dafür 
gibt.

Und dass das mit C++-String-Funktionen wahrscheinlich viel lesbarer ist 
als mit C-char[]-Funktionen wurde ja auch schon erwähnt.

MfG, Arno

von Cyblord -. (cyblord)


Lesenswert?

Dirk B. schrieb:
> Das geht solange gut, bis Systeme mit verschiedener Endianess
> aufeinander treffen.
> Dann steigt der Aufwand.

Nicht wirklich. Das siehst du daran dass man für Netzwerkkommunikation 
gerne die htonl, htons, ntohl, ntohs Funktionen verwendet. Und dann 
spielt die Endianess plötzlich keine Rolle mehr.

von EAF (Gast)


Lesenswert?

Cyblord -. schrieb:
> Und dann spielt die Endianess plötzlich keine Rolle mehr.
Auf Kosten einer dazwischen geschobenen Schicht.

Eine solche ist die Klartext/Ascii Schicht auch.
Zudem von Menschen lesbar.

Man kann sich über das "Maschine zu Maschine" Protokoll streiten.
Keine Frage.
Aber eindeutig, das muss es sein, dazu gibt es keine Alternative.

von 50c (Gast)


Lesenswert?

EAF schrieb:
> (Regen ist nass)

...aber nur, wenn kein Sturm ist!

von foobar (Gast)


Lesenswert?

Les dir mal die man-Page zu strncpy durch - sie macht nicht das, was du 
vermutest.

von PittyJ (Gast)


Lesenswert?

foobar schrieb:
> Les dir mal die man-Page zu strncpy durch - sie macht nicht das,
> was du
> vermutest.

Deshalb auch mein Vorschlag mit std::string. Damit braucht man die 
gefährlichen K&R Stringroutinen nicht. Selbst bei strncpy() muss man 
evtl hinten noch ein '\0' einsetzen. Das kann ein Anfänger nicht wissen. 
Deshalb sollte es die Finger davon lassen.

von Matthias S. (mat-sche)


Lesenswert?

PittyJ schrieb:
> Deshalb auch mein Vorschlag mit std::string. Damit braucht man die
> gefährlichen K&R Stringroutinen nicht. Selbst bei strncpy() muss man
> evtl hinten noch ein '\0' einsetzen. Das kann ein Anfänger nicht wissen.
> Deshalb sollte es die Finger davon lassen.

Dann gib mir bitte ein Beispiel.

> evtl hinten noch ein '\0' einsetzen. Das kann ein Anfänger nicht wissen.
> Deshalb sollte es die Finger davon lassen.

Wenn Du meinen Code angeschaut hast, habe ich schon daran gedacht, 
wohlmöglich aber nicht richtig umgesetzt.
Wie gesagt, der Hauptteil vom Code funktioniert, auch die CRC Berechnung 
mit Vergleich.
Ih versuch nun mal mich mit den von Dir vorgeschlagenen "std::string" zu 
befassen.

von Matthias S. (mat-sche)


Lesenswert?

foobar schrieb:
> Les dir mal die man-Page zu strncpy durch - sie macht nicht das, was du
> vermutest.
OK, was vermute ich denn?
Und was muss ich denn dabei beachten bzw. was läuft bei dem Code den 
falsch?

von foobar (Gast)


Lesenswert?

> was vermute ich denn?

Ok, ich hab falsch vermutet, sorry.  Dein Kode ist so unleserlich 
(wirklich, als ob er durch einen Obfuscator gejagt wurde; die Spaces am 
Zeilenende geben ihm den Rest), dass ich nur das Ende gelesen und den 
typischen strncpy Fehler gesehen habe (ein String ist länger als 
erwartet).

Du versucht, das Problem durch explizite "dst[len-1]=0" zu beheben, hast 
dich dabei aber hier wohl verrannt:
1
>   anzahl = komma[count_[0]-1] - komma[0];
2
>
3
>   // # Daten zwischen den Kommas in Daten_1 kopieren
4
>   strncpy(Daten_1,chararray_ser + komma[0],anzahl);
5
>   Daten_1[komma[count_[0]-1]] = '\0';

"Daten_1[anzahl-1] = 0"

von Matthias S. (mat-sche)


Lesenswert?

Arno schrieb:
> Verdacht: Du kopierst anzahl Zeichen nach Daten1[], setzt dann aber
> nicht das Zeichen an Position anzahl auf \0, sondern das Zeichen an
> Position komma[count_[0] -1 ]. Und da vorher schon was in Daten1[]
> drinstand, bleibt das da.

Hallo Arno,

vielen Dank für Deinen Beitrag! Dieser Teil hat mich auf die richtige 
Spur gebracht und nach suchen/lesen zur Funktion "strncpy" hab ich diese 
verstanden.
Der Fehler war, dass ich die Null Terminierung nicht richtig gesetzt 
hatte.
Jetzt geht es!
Warum nicht die "überholten" C-Stringfunktionen benutzen?, Geht doch ;)

Arno schrieb:
> Tipp: Nach jedem Schritt alle Zwischenergebnisse (mit Zeilennummer)
> ausgeben oder im Debugger anzeigen, dann solltest du selbst darauf
> kommen.

Debuggen in Arduino? Wie geht das. Über kurz oder lnag werd ich wohl als 
IDE auf Visual Studio Code umsteigen, da sollte es ja funktionieren...
Oder hast Du einen anderen Vorschlag?

Arno schrieb:
> Und mittelfristig, um solche Fehler nicht zu wiederholen: Viel, viel
> weniger Chaos produzieren ;)

gib mir bitte ein Beispiel, was Deiner Ansicht Chaos ist und zeige mir, 
wie es besser sein könnte. Will ja gern lernen :)

Arno schrieb:
> Die
> String-Funktionen haben auch Rückgabewerte, die man nutzen kann und
> sollte.
Wie sieht denn der Rückgabewert bei "strncpy" aus?

Grundsätzlich würde mich jedoch interessieren wie ein "Profi" den String 
auseinander nehmen würde...
[_A,index,2.90,221,37.29,34.78,41.76,]647B
Brauche die Daten zwischen den Kommas :)

Vielen DAnk nochmals :)

von Matthias S. (mat-sche)


Lesenswert?

foobar schrieb:
> Ok, ich hab falsch vermutet, sorry.  Dein Kode ist so unleserlich
> (wirklich, als ob er durch einen Obfuscator gejagt wurde; die Spaces am
> Zeilenende geben ihm den Rest), dass ich nur das Ende gelesen und den
> typischen strncpy Fehler gesehen habe (ein String ist länger als
> erwartet).

Hi foobar!

Danke für die Antwort!
ich räume den Code jetzt weiter auf. Inzwischen habe ich meinen Fehler 
gefunden, habe die ganze Zeit gedacht, dass ich die Nullterminierung 
richtig gesetzt hatte. Da lag mein Fehler!
1
 anzahl = komma[count_-1] - komma[0];
2
 strncpy(Daten_1,chararray_ser + komma[0],anzahl);
3
 Daten_1[anzahl] = '\0';

foobar schrieb:
> Dein Kode ist so unleserlich
> (wirklich, als ob er durch einen Obfuscator gejagt wurde;

Das mag für ein Profi so sein ;)

Ich hatte mir einen Kopf gemacht, wie ich aus einem Chararray, unter zu 
Hilfenahme der str-Funktionen, die gewünschten Variablen 
herausbekomme....

von Harry L. (mysth)


Lesenswert?

Matthias S. schrieb:
> Grundsätzlich würde mich jedoch interessieren wie ein "Profi" den String
> auseinander nehmen würde...
> [_A,index,2.90,221,37.29,34.78,41.76,]647B
> Brauche die Daten zwischen den Kommas :)

Mit strtok
https://man7.org/linux/man-pages/man3/strtok.3.html

von foobar (Gast)


Lesenswert?

> Grundsätzlich würde mich jedoch interessieren wie ein "Profi" den
> String auseinander nehmen würde...

Wenn der String in einem beschreibbaren Puffer liegt, würde ich gar 
nichts kopieren - im Prinzip die Komma durch \0 ersetzen und die 
Positionen merken

Z.B. so:
1
#define NELEM(x) (sizeof(x) / sizeof(*(x)))
2
3
// split str at delim (in place)
4
// stores substrings in res[], returns nr of delim found
5
int split(char *str, char delim, char **res, int nres)
6
{
7
    int n = 0;
8
9
    res[n] = str;
10
    while (*str)
11
        if (*str++ == delim)
12
        {
13
            str[-1] = 0;
14
            if (++n < nres)
15
                res[n] = str;
16
        }
17
    return n;
18
}
19
20
void parse_msg(char *msg)
21
{
22
    char *p, *field[5];
23
    unsigned crc;
24
25
    if (*msg++ == '[' && (p = strchr(msg, ']')))
26
    {
27
        crc = crc16(msg, p-msg, 0x1021, 0, 0, false, false);
28
        *p++ = 0;
29
        if (*p && strtoul(p, &p, 16) == crc && *p == 0)
30
            if (split(msg, ',', field, NELEM(field)) == 4)
31
            {
32
                printf("Field 1: %s\n", field[0]);
33
                printf("Field 2: %s\n", field[1]);
34
                printf("Field 3: %s\n", field[2]);
35
                printf("Field 4: %s\n", field[3]);
36
                printf("Field 5: %s\n", field[4]);
37
            }
38
    }
39
}

von Matthias S. (mat-sche)


Lesenswert?

foobar schrieb:
> Z.B. so:

Wau... Auf so etwas würde ich nie kommen. Das muss ich erst einmal 
durchgehen und versuchen zu verstehen! Aber ich bin noch lange nicht 
soweit das zu verstehen, dazu bräuchte ich einen Telefon Joker ;)
Das ist nicht mein Handwerk, mache lieber meinen Garten schön :) 
(bezogen auf den Anfangspost)
Danke für Deine Mühen!
MAT

von Dirk B. (dirkb2)


Lesenswert?


von Dirk B. (dirkb2)


Lesenswert?

Matthias S. schrieb:
> Grundsätzlich würde mich jedoch interessieren wie ein "Profi" den String
> auseinander nehmen würde...
> [_A,index,2.90,221,37.29,34.78,41.76,]647B
> Brauche die Daten zwischen den Kommas :)

Wenn du statt Kommas Whitespace (Leerzeichen oder Tabulator) nehmen 
würdest, kannst da das ganz einfach mit sscanf machen.

sscanf(buffer,“[%s %s %s %s %s %s %s ] %s“, …)

mit Komma
sscanf(buffer,“[%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],] %s“, …)
Für die … kommen 7 Adressen von char-Arrays.

Du kannst die Werte auch gleich im richtigen Format (%f %x %d) lesen.

von Matthias S. (mat-sche)


Lesenswert?

Dirk B. schrieb:
> Wenn du statt Kommas Whitespace (Leerzeichen oder Tabulator) nehmen
> würdest, kannst da das ganz einfach mit sscanf machen.

Super!
Mein erdachtes Protokoll kann ich jederzeit ändern!
Es gibt unendliche Möglichkeiten, wie soll man darauf als Laie kommen, 
Danke für die Hilfen hier!

von Dirk B. (dirkb2)


Lesenswert?

Matthias S. schrieb:
> Dirk B. schrieb:
>> Wenn du statt Kommas Whitespace (Leerzeichen oder Tabulator) nehmen
>> würdest, kannst da das ganz einfach mit sscanf machen.
>
> Super!

Die meisten Formatspecifier von scanf überlesen Whitespace am Anfang und 
hören auf, wenn kein passendes Zeichen mehr gefunden wurde.
Ein Whitespace im Formatstring steht für beliebig viele Whitespace im 
Text.
Dabei ist es egal, welches Whitespace (Leerzeichen ' ', Tabulatoren '\t' 
'\f', Zeilenvorschub '\n', Wagenrücklauf '\r') ist.

Das erste Beispiel läßt sich auch auf sscanf(buffer,“[%s%s%s%s%s%s%s 
]%s“, …)
kürzen.

scanf ist eine komplexe Funktion und damit recht teuer (Speicherplatz, 
Laufzeit)

von Matthias S. (mat-sche)


Lesenswert?

Dirk B. schrieb:
> scanf ist eine komplexe Funktion und damit recht teuer (Speicherplatz,
> Laufzeit)

Das ist ein guter Hinweis, ich arbeite hier auf einem ESP und bin noch 
nicht richtig konfirm, was darauf alles möglich ist.

von Stefan F. (Gast)


Lesenswert?

Ich würde diesen Parser auf einem PC entwickeln, testen und debuggen. 
Erst danach ins Arduino Projekt einfügen.

> Mein erdachtes Protokoll kann ich jederzeit ändern!

Dann mache das. Etwas Text basiertes mit Label ist viel einfacher zu 
parsen:
1
raum:Wohnzimmer
2
temp_soll:21.5
3
temp_ist:21.0
4
fenster:offen
5
tuere:geschlossen

Eine Leerzeile danach kennzeichnet das Ende des Datensatzes. So 
funktioniert übrigens das allgegenwärtige HTTP Protokoll.

von Harry L. (mysth)


Lesenswert?

Dirk B. schrieb:
> Harry L. schrieb:
>> Mit strtok
>> https://man7.org/linux/man-pages/man3/strtok.3.html
>
> Nein.
> Wenn strtok_r

Blödsinn!
Der TO hat noch ganz andere Probleme als Rekursionen.

von foobar (Gast)


Lesenswert?

> Blödsinn! Der TO hat noch ganz andere Probleme als Rekursionen.

Dirk hat schon recht: Wenn strtok, dann strtok_r.  Hat mit Rekursion 
nichts zu tun, einfach nur verschachtelte strtok-Aufrufe.


> sscanf(buffer,“[%s %s %s %s %s %s %s ] %s“, …)

Das Problem bei sscanf steckt in den "…": Jedes "%s" bzw "%[...]" 
braucht einen eigenen Buffer, der mind so groß wie "buffer" ist - das 
wird, insb auf Mikrocontrollern mit wenig RAM, eklig.


> Arduino ist C++. Da geht auch std::string

Sicher, dass Arduino std::string hat?  Ich hatte den Eindruck, das 
gibt's da nicht.  Selbst wenn: dynamische Speicherverwaltung (wie u.a. 
von std:string verwendet) ist auf Mikrocontrollern problematisch (wenig 
RAM, Fragmentierung, OOM, ...).  Wenn nicht unbedingt nötig, vermeiden.

von Harry L. (mysth)


Lesenswert?

foobar schrieb:
> Dirk hat schon recht: Wenn strtok, dann strtok_r.  Hat mit Rekursion
> nichts zu tun, einfach nur verschachtelte strtok-Aufrufe.

Ach?
Genau DAS nennt man dann Rekursion.

Zitat aus der Man-Page:
> The strtok_r() function is a reentrant version of strtok().

Sowas braucht man u.A. bei Rekursionen, aber ganz sicher nicht in dem 
hier beschrieben Scenario.

W.g.: der TO kämpft derzeit noch viel simpleren Problemen.
Für strtol_r gibt es hier absolut keinen Grund.

von foobar (Gast)


Lesenswert?

>> Dirk hat schon recht: Wenn strtok, dann strtok_r.  Hat mit Rekursion
>> nichts zu tun, einfach nur verschachtelte strtok-Aufrufe.
>
> Ach?  Genau DAS nennt man dann Rekursion.

Nein, zwei verschachtelte Schleifen sind noch keine Rekursion.
1
#include <stdio.h>
2
#include <string.h>
3
4
//#define strtok_r(a,b,c) strtok((a),(b))
5
6
void test(char *str)
7
{
8
    char *state1, *state2;
9
10
    printf("string: '%s'\n", str);
11
    for (char *word; word = strtok_r(str, " ", &state1); str = 0)
12
    {
13
        printf("  word: '%s'\n", word);
14
        for (char *field; field = strtok_r(word, ",", &state2); word = 0)
15
            printf("    field: '%s'\n", field);
16
    }
17
}
18
19
int main(int argc, char **argv)
20
{
21
    char buf[] = "a,b  c,d  e,f,g";
22
    test(buf);
23
    return 0;
24
}

Lass das mal ohne und mit dem "#define" laufen (also einmal mit strtok_r 
und einmal mit strtok).  Bei strtok ist nach dem ersten "word" 
Feierabend, die folgenden Wörter werden nicht mehr behandelt.  Besonders 
lustig wird's, wenn die innere Schleife in einer Unterroutine steckt und 
man gar nicht erwartet hat, dass die strtok benutzt.  Analog: wenn der 
Aufrufer von test auch zufälligerweise strtok nutzt, zerhaut's den.

An sich gehört strtok aus dem Standardlibrary rausgeschmissen - nur der 
Kompatibilität wegen gibt's das noch.

von Rolf M. (rmagnus)


Lesenswert?

Harry L. schrieb:
> Der TO hat noch ganz andere Probleme als Rekursionen.

Das _r steht nicht für "rekursiv", sondern für "reentrant".

Harry L. schrieb:
> foobar schrieb:
>> Dirk hat schon recht: Wenn strtok, dann strtok_r.  Hat mit Rekursion
>> nichts zu tun, einfach nur verschachtelte strtok-Aufrufe.
>
> Ach?
> Genau DAS nennt man dann Rekursion.

Rekursion ist, wenn etwas (direkt oder indirekt) sich selbst aufruft. 
Das macht strtok nicht.

von da aus wo ich gucke (Gast)


Lesenswert?

Matthias S. schrieb:
> Dirk B. schrieb:
>> scanf ist eine komplexe Funktion und damit recht teuer (Speicherplatz,
>> Laufzeit)
>
> Das ist ein guter Hinweis, ich arbeite hier auf einem ESP und bin noch
> nicht richtig konfirm, was darauf alles möglich ist.

Ich setze noch einen obenauf.

Um die Denke weiter zu trainieren, hilft es m.M.n. weiter weg von der 
kleinteiligen uC-Welt zu gehen, erst danach wieder auf 
RAM-&MHz-limitierte implementation zurückzukommen.

Ich mag PCRE, insbesondere in der Pythonimplementation welche direkt 
Dictionary zurückliefert.

Als Übung empfehle ich mal den NMEA Datenstrom eines 
Navis/GPS-Rx(strings!) per (USB)seriellen schnittstelle am PC einzulesen 
und und ein paar Datenfelder rauszupicken.

Bei geschicktem vorgehen (wenn der Groschen fällt) ergibt sich ein klar 
erkennbares generisches Muster an PCRE, welches sich dann einfach auf 
weitere Datenfelder ausbauen lässt und zwar OHNE weiteren Programmcode 
schreiben zu müssen sondern eben bloss weitere PCRE-Schnipsel 
hinzuzufügen.

Das lässt sich dann natürlich nicht auf "Arduino stufe" runterbrechen 
(C, C++, stdlib, mit/ohne sscanf, ...) aber lichtet das Chaos im kopp 
und gibt einem eine Vision/Leitfaden wie Protokoll und dessen Behandlung 
aussehen könnte.

Mit gegebenen Einschränkungen der Zielplattform/Umgebung kann man dann 
den sinnvoll nötigen minimalteil davon schon umsetzen.

Dieser Input hier von mir will auch eine gebrochene Lanze dafür sein, 
dass  eine zusätzliche ganz andere Programmiersprache (i.deren Libs) als 
jene welche man gerade verwenden will/muss eine sehr Grosse und 
nützliche Bereicherung ist.

von Matthias S. (mat-sche)


Lesenswert?

Harry L. schrieb:
>> Nein.
>> Wenn strtok_r
>
> Blödsinn!
> Der TO hat noch ganz andere Probleme als Rekursionen.

Liebes Forum,

coole Sache Eure Hilfe!
strtok_r ist schon ganz gut und habe ich auch in Benutzung.

foobar schrieb:
> Dirk hat schon recht: Wenn strtok, dann strtok_r.  Hat mit Rekursion
> nichts zu tun, einfach nur verschachtelte strtok-Aufrufe.

Jup so ist es! Strtok ist nicht wiedereintrittsfähig, das heisst, ich 
kann keine weiter Suchdurchläufe in Verschachtelung betreiben. Soviel 
habe ich auch im Netz mir erarbeitet.

foobar schrieb:
>> sscanf(buffer,“[%s %s %s %s %s %s %s ] %s“, …)
>
> Das Problem bei sscanf steckt in den "…": Jedes "%s" bzw "%[...]"
> braucht einen eigenen Buffer, der mind so groß wie "buffer" ist - das
> wird, insb auf Mikrocontrollern mit wenig RAM, eklig.

Genau das ist es, ich habe ja geschrieben, dass mein Zielsystem ein 
ESP8266 ist. Und alles gut und schön mit den Funktionen unter C++, nur 
wenn ein Anfänger nicht weiß, was darin vorgeht oder es an Recourcen 
benötigt, handelt man sich schnell Probleme ein, die größer sind als die 
schon vorhandene Unwissenheit :)

foobar schrieb:
>> Arduino ist C++. Da geht auch std::string
>
> Sicher, dass Arduino std::string hat?  Ich hatte den Eindruck, das
> gibt's da nicht.  Selbst wenn: dynamische Speicherverwaltung (wie u.a.
> von std:string verwendet) ist auf Mikrocontrollern problematisch (wenig
> RAM, Fragmentierung, OOM, ...).  Wenn nicht unbedingt nötig, vermeiden.

Jup, dass habe ich mir dann im Netz auch erlesen und das ist das gleiche 
Problem siehe sscanf.......
foobar Du hast es auf den Punkt gebracht! Danke.

Harry L. schrieb:
> W.g.: der TO kämpft derzeit noch viel simpleren Problemen.
> Für strtol_r gibt es hier absolut keinen Grund.

Mist, habt mich erwischt ;)
Strtok_r ist schon richtig gut, so könnte man den String nach 
unterschiedlichen Trennzeichen auseinander nehmen, bin aber noch nicht 
darauf gekommen wie, hab da noch einen Knoten im Kopf.

So ich werde mal weiter machen, mein Eingangsproblem habe ich gelöst und 
dabei gelernt! Sicherlich ist das alles noch nicht optimal aber das wird 
schon noch (hoffe ich :) ).

von Christoph M. (mchris)


Lesenswert?

Matthias S. (mat-sche)
18.02.2022 17:19
>sitze hier schon seit tagen drann und komm nicht weiter.
>Ich habe einen String : [_A,index,2.80,182,]E6B1
>Ich benötige in einzellnen Variablen: ,index,2.80,182,

Ich nutzte gerne das Teilen eines Strings in zwei Hälften.
Wie wäre es damit?:
1
void setup()
2
{
3
  Serial.begin(115200);
4
}
5
6
String rightString(String s)
7
{
8
  String s2 = s.substring(s.indexOf(',') + 1); // right string
9
  return s2;
10
}
11
12
String leftString(String s)
13
{
14
  String s2 = s.substring(0, s.indexOf(',')); // left string
15
  return s2;
16
}
17
18
void loop()
19
{
20
  String s = "[_A,index,2.80,182,]E6B1";
21
22
  String s1 = rightString(s);
23
  //String s1 = "index,2.80,182,]E6B1";
24
  String idx = leftString(s1);
25
  Serial.println(idx);
26
27
  String s2 = rightString(s1);
28
  //String s2 = "2.80,182,]E6B1";
29
  //Serial.println(s2);
30
  
31
  String fs1=leftString(s2);
32
  float f1=fs1.toFloat();
33
  Serial.println(f1);
34
35
  String s3 = rightString(s2);
36
  //String s2 = "182,]E6B1";
37
  //Serial.println(s3);
38
  String s4=leftString(s3);
39
  float f2=s4.toFloat();
40
  Serial.println(f2);
41
  
42
  delay(1000);
43
}

Output:
1
index
2
2.80
3
182.00

von da aus wo ich gucke (Gast)


Lesenswert?

> Ich nutzte gerne das Teilen eines Strings in zwei Hälften.
> Wie wäre es damit?:
>
>
1
> String rightString(String s)
2
> {
3
>   String s2 = s.substring(s.indexOf(',') + 1); // right string
4
>   return s2;
5
> }
6
> 
7
> String leftString(String s)
8
> {
9
>   String s2 = s.substring(0, s.indexOf(',')); // left string
10
>   return s2;
11
> }
12
>

Ein Zwischenschritt um im Kopf die Ideen zu ordnen, ja.

Aber ausgerechnet auf einer limitierten Zielplattform immer wieder die 
selbe Position desselben Trennzeichens ',' zu ermitteln und wieder zu 
vergessen (lokale Variable) um es in der nächsten Funktion abermals zu 
ermitteln... Ist halt "wer es nicht im Kopf hat, hat es in den Beinen".

Auch: wie verhalten sich als lokale Variablen angelegte 
String-Instanzen? Und was passiert damit wenn als rückgabewert der 
Funktion gebraucht? (das muss nicht falsch sein, aber gut zu wissen wie 
sich das auswirkt...)

Dann lieber die Positionen der nächsten z.B. 7 (wieviele werden es 
maximal? Auch in zukunft?) Trennzeichen ermitteln und damit 
rumschnippeln, Idealerweise ohne ständig Teilstrings rumzukopieren. 
Weil: limitierte Zielplattform.

von Cyblord -. (cyblord)


Lesenswert?

Stefan ⛄ F. schrieb:
> Dann mache das. Etwas Text basiertes mit Label ist viel einfacher zu
> parsen:
> raum:Wohnzimmer
> temp_soll:21.5
> temp_ist:21.0
> fenster:offen
> tuere:geschlossen

Dann wenigstens gleich JSON, dafür gibts fertige Parser für C.

von Jobst Q. (joquis)


Lesenswert?

foobar schrieb:
> Wenn der String in einem beschreibbaren Puffer liegt, würde ich gar
> nichts kopieren - im Prinzip die Komma durch \0 ersetzen und die
> Positionen merken

Das mache ich ähnlich. Allerdings sieht meine split-Funktion anders aus 
und behandelt nur das jeweils nächste Trennzeichen. Dadurch wird das 
Array überflüssig.
1
char * split(char *s,char c){
2
while (*s!=c && *s!=0)s++;
3
if (*s==c)*s++=0;
4
return s;
5
}
Zurückgegeben wird ein Zeiger auf den Rest des Strings oder auf die 
Endnull, wenn kein Trennzeichen gefunden wurde.

Das Parsen würde etwa so aussehen:
1
...
2
s=buf;
3
for(i=0;*s;i++){
4
  sr=split(s,',');
5
  switch (i){
6
    case 0: svar0= strdup(s);break; //_A
7
    case 1: svar1= strdup(s);break; //index
8
    case 2: fvar = strtof(s,0);break; //2.80
9
    case 3: ivar = strtol(s,0,10);break; // 182
10
    }
11
  s=sr;
12
  } //for
13
...

von Matthias S. (mat-sche)


Lesenswert?

Jobst Q. schrieb:
> Das mache ich ähnlich. Allerdings sieht meine split-Funktion anders aus
> und behandelt nur das jeweils nächste Trennzeichen. Dadurch wird das
> Array überflüssig.

Ich versuch gerad zu verstehen, wie ich dies für meinen String anwenden 
kann. Kannst Du mir bitte dies an 
[_A,index,2.90,221,37.29,34.78,41.76,]647B verdeutlichen?

von Dirk B. (dirkb2)


Lesenswert?

Jobst Q. schrieb:
> strdup(s);

strdup?

Echt jetzt?

von Stefan F. (Gast)


Lesenswert?

da aus wo ich gucke schrieb:
> Ist halt "wer es nicht im Kopf hat, hat es in den Beinen".

Ja schon, andererseits ist der Code so leichter lesbar. Wenn die 
Performane an dieser Stelle unkritisch ist, würde ich die besser lesbare 
Version bevorzugen.

Manchmal leistet der Optimizer des C Compiler aber auch erstaunliches. 
Zum Beispiel wird hier die teure Division nicht zweimal durchgeführt, 
obwohl es der Quelltext suggeriert.
1
#include <stdio.h>
2
3
void zeit_ausgeben(int sekunden)
4
{
5
   int min=sekunden/60;
6
   int sec=sekunden%60;
7
   printf("%d:%02d\n",min,sec);
8
}
9
10
int main()
11
{
12
    zeit_ausgeben(132);
13
}

von Christoph M. (mchris)


Lesenswert?

da aus wo ich gucke (Gast)
>Auch: wie verhalten sich als lokale Variablen angelegte
>String-Instanzen? Und was passiert damit wenn als rückgabewert der
>Funktion gebraucht? (das muss nicht falsch sein, aber gut zu wissen wie
>sich das auswirkt...)

Es hindert dich niemand daran, dass herauszufinden.

>Dann lieber die Positionen der nächsten z.B. 7 (wieviele werden es
>maximal? Auch in zukunft?) Trennzeichen ermitteln und damit
>rumschnippeln, Idealerweise ohne ständig Teilstrings rumzukopieren.
>Weil: limitierte Zielplattform.

Jede Platform ist limitiert und der hier angestrebte ES8266 ist es schon 
weniger als ein Atmega328.

Aber da mir meine erste Lösung auch nicht so gute gefallen hatte, hier 
die nächste:
1
void setup()
2
{
3
  Serial.begin(115200);
4
}
5
6
void loop()
7
{
8
  String idx;
9
  float a, b, c, d, e;
10
11
  uint8_t start, stop;
12
13
  String s = "[_A,index,2.90,221,37.29,34.78,41.76,]647B";
14
15
  Serial.println("=============");
16
17
  start = s.indexOf(',') + 1;
18
  stop = s.indexOf(',', start);
19
  idx = s.substring(start, stop);
20
21
  start = stop + 1;
22
  stop = s.indexOf(',', start);
23
  a = s.substring(start, stop).toFloat();
24
25
  start = stop + 1;
26
  stop = s.indexOf(',', start);
27
  b = s.substring(start, stop).toFloat();
28
29
  start = stop + 1;
30
  stop = s.indexOf(',', start);
31
  c = s.substring(start, stop).toFloat();
32
33
  start = stop + 1;
34
  stop = s.indexOf(',', start);
35
  d = s.substring(start, stop).toFloat();
36
37
  start = stop + 1;
38
  stop = s.indexOf(',', start);
39
  e = s.substring(start, stop).toFloat();
40
41
  Serial.println(idx);
42
  Serial.println(a);
43
  Serial.println(b);
44
  Serial.println(c);
45
  Serial.println(d);
46
  Serial.println(e);
47
48
  delay(1000);
49
}

von Matthias S. (mat-sche)


Lesenswert?

Christoph M. schrieb:
> Aber da mir meine erste Lösung auch nicht so gute gefallen hatte, hier
> die nächste:

Das nenne ich mal einfach und gut durchdacht! Habe auf der Arduino 
Webseite dier : Reference > Language > Variables > Data types > String > 
Functions >
gefunden.... Die hilft auch weiter.
Dein Beispiel werd ich wohl mir näher ansehen und implementieren.
Danke!

von Christoph M. (mchris)


Lesenswert?

>Das nenne ich mal einfach und gut durchdacht!

Ah, danke für's Lob.

Es lohnt sich, die String Funktionen mal genau anzusehen:

https://www.arduino.cc/reference/de/language/variables/data-types/stringobject/

Noch ein kleiner Hinweis: beim obigen Code wird für "index" immer das 
Wort index geholt. Möglicherweise willst Du aber das "_A" statt dem Word 
"index". An der Stelle müsste der Code dann noch angepasst werden.

von Jobst Q. (joquis)


Lesenswert?

Dirk B. schrieb:
> Jobst Q. schrieb:
>> strdup(s);
>
> strdup?
>
> Echt jetzt?

War nur als Beispiel für längere Weiterverwendung des Strings. Solange 
keine neuen Daten kommen, reicht auch  svar1=s;

Ich benutze es eigentlich so gut wie nie, da es per malloc arbeitet und 
später wieder ein free() erfordert. Für Mikrocontroller ist es schon 
garnicht zu empfehlen.

von Jobst Q. (joquis)


Lesenswert?

Matthias S. schrieb:
> Jobst Q. schrieb:
>> Das mache ich ähnlich. Allerdings sieht meine split-Funktion anders aus
>> und behandelt nur das jeweils nächste Trennzeichen. Dadurch wird das
>> Array überflüssig.
>
> Ich versuch gerad zu verstehen, wie ich dies für meinen String anwenden
> kann. Kannst Du mir bitte dies an
> [_A,index,2.90,221,37.29,34.78,41.76,]647B verdeutlichen?

In meinem Beispiel zum Parsen habe ich doch schon die ersten 4 Felder 
deines ersten Postings im Kommentar. Du müsstest es nur noch um case 5 
und 6 erweitern. Bei noch mehr Feldern entsprechend mehr cases.

Am Anfang kannst du den CRC-String auch mit split abtrennen:

s_crc= split (s,']');  Um das erste [ zu entfernen reicht s++;

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.