Go Down

Topic: unregelmässigen "CSV-String" parsen (Read 1 time) previous topic - next topic

hk007

Hi Leute,

heut bräuchte ich mal wieder einen Denkanstoss:
Folgender Fall:
ich bekomme über die serielle Schnittstelle einen ASCII-String. In dem String sind x Werte durch Komma getrennt.
Wenn ein Wert nicht existiert, dann steht da auch nichts drin, sondern es kommt gleich das nächste Komma.
Das heisst, daß ich die Datenwerte in meinem In-String nicht immer an den selben Stellen auslesen kann.

Das einzige was mir jetzt einfällt, ist, dass man beim Einlesen schaut, ob nach einem Komma das nächste Zeichen wieder ein Komma ist, und dann den Wert mit "Null" abspeichert.
Oder habt ihr da eine schlauere oder elegantere Idee, wie man das programmieren kann? Dazu kommt noch, daß die Werte, abhängig von der Größe, 1-3 Zeichen lang sein können.

Code: [Select]
Bsp.1: $3,2,,,,,,,,00,,,,,18,,,<\r>
Bsp.2: $3,2,09,26,30,156,36,12,26,231,00,28,25,054,44,18,21,277,00<\r>


gruß/hk007
Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

mkl0815

Wander einfach durch den String und zähle die Kommas und speichere deren Position im String in einem Array (z.B. byte kommas[20]).
Wenn Du den 5. Wert haben willst, ist das dann der Teilstring von Position (kommas[5-2]+1) bis Position (kommas[5-1]-1).
Das kann man z.B. super in eine einzelne Funktion giessen.

Eisebaer

hi,

sollte das nicht mit split(";") funktionieren?

gruß stefan

michael_x

Sind doch alles Zahlen, oder ?

Wenn ja, dann wandele sie gleich, während du die Kommas suchst:

Code: [Select]
char datastring = "$3,2,,,,,,,,00,,,,,18,,,\r";
char * p = datastring+1; // nach dem '$'

int val=0;  // temp variable

int dataArray[20];
int i = 0;   // Index auf dataArray

while ( *p != '\r' && *p != 0)
{
   if (*p == ',')  // Zahl fertig
   {
      dataArray[i++] = val;
      val = 0;
   }
   else if ( *p >= '0' && *p <= '9' )
      val = val*10 + *p - '0'; // einfachste ascii -> int Wandlung
}
     dataArray[i] = val; // den letzten Wert nicht vergessen

Wenn du auch negative Zahlen hast, musst du ein bisschen was ergänzen ;)

Ich hoffe,  "$0,0,000,0" ist das gleiche wie  "$,,,," 
sonst musst du natürlich was anderes machen.

hk007

HI,

danke an alle Vorschläge.

Ich hab mir das von michael_x mal genauer angeschaut.

So auf Anhieb krieg ichs nicht hin:
Ein paar Sachen hab ich mal ergänzt, damit man es kompilieren kann:
Code: [Select]
//char datastring = "$33,22,11,4,5,6,,,,00,,,,,18,,,\r"; ---> geändert
char datastring[] = "$33,22,11,4,5,6,,,,00,,,,,18,,,\r";
char *p = datastring + 1; // nach dem '$'

int val=0;  // temp variable
int dataArray[20];
int i = 0;   // Index auf dataArray

while ( *p != '\r' && *p != 0)
{
   if (*p == ',')  // Zahl fertig
   {
     dataArray[i++] = val;
      val = 0;
   }
   else if ( *p >= '0' && *p <= '9' )
      val = val*10 + *p - '0'; // einfachste ascii -> int Wandlung
      p++; ---------------------> eingefügt
}
     dataArray[i] = val; // den letzten Wert nicht vergessen

Serial.println (dataArray[1]);
Serial.println (dataArray[2]);
Serial.println (dataArray[3]);
Serial.println (dataArray[4]);
Serial.println (dataArray[5]);
Serial.println (dataArray[6]);
Serial.println (dataArray[7]);


Wenn ich es laufen lasse, dann gibt das Terminal folgendes aus:
Code: [Select]
erster Durchlauf:
22
11
4
5
6
0
0
zweiter Durchlauf:
$22
11
4
5
6
0
0



Das sieht so weit gut aus. Nur die erste Zahl fehlt mir immer. Und ich schlepp aus dem alten Lauf was mit.
Das finde ich schon noch raus.
Aber ich verstehe nur eine Zeile nicht so ganz:
char *p = datastring + 1; // nach dem '$'
Was ist jetzt "p"? Ist das der Pointer auf das Zeichen im Datastring, oder ist es das Zeichen selber?? Da fehlts mir etwas an "C-Kenntnissen"

gruß/hk007
Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

hk007

#5
Aug 31, 2012, 04:48 pm Last Edit: Aug 31, 2012, 04:52 pm by hk007 Reason: 1
Oh ich Esel,

Ich muss natürlich bei den println-Befehlen auch das array[0] mit anzeigen.
Gut, wenn das mit drinsteht, dann sieht es so aus:

Code: [Select]
erster Durchlauf:
33
22
11
4
5
6
0
0
zweiter Durchlauf:
$33
22
11
4
5
6
0
0
dritter Durchlauf:
G33
22
11
4
5
6
0
0


Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Udo Klein

Also ich würde für sowas einen "Stream Parser" bauen. Wie das geht? Morgen 00:01 ist der Beitrag http://blog.blinkenlight.net/experiments/measurements/flexible-sweep/ öffentlich. Da trete ich das Problem mal so richtig breit ;)
Check out my experiments http://blog.blinkenlight.net

michael_x

Sorry für meinen Tipp-Fehler:
char datastring[]  ist natürlich richtig

char * p = datastring;  heisst: p ist ein pointer auf datastring. p+1 ( oder datastring+1 ) zeigt auf das 2. Zeichen   p++ erhöht den pointer.
( sorry nochmal )

*p ist dann vom Datentyp char => das Zeichen auf das p zeigt.

Ist doch ganz einfach ;)

hk007


Sorry für meinen Tipp-Fehler:


Musst dich doch nicht entschuldigen. Bin um jedes Codeschnitzel froh :-)
Das mit dem zusäzlichen Zeichen war mein Fehler. Hatte in der Void loop() noch eine Codeleiche, die reingespukt hat.  :smiley-sad-blue:
Läuft jetzt.

Aber ich werd mir die Idee von mkl0815 auch noch mal anschauen.

gruß/hk007



Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Udo Klein

Mein neuestes Experiment ist jetzt draussen. Du kannst den Parser von dort einfach übernehmen. Du musst für Deinen Anwendungsfall nur bei

Code: [Select]

    const char terminator[] = " \t\n\r";


den Tab durch das Komma ersetzen, und newline wegnehmen, also

Code: [Select]

    const char terminator[] = " ,\r";


und weiterhin max_fractional_digits auf 0 setzen.
Check out my experiments http://blog.blinkenlight.net

Go Up