Pages: [1]   Go Down
Author Topic: unregelmässigen "CSV-String" parsen  (Read 1003 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Sr. Member
****
Karma: 3
Posts: 385
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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
Logged

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

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Wien
Offline Offline
Edison Member
*
Karma: 28
Posts: 1894
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi,

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

gruß stefan
Logged

Germany
Offline Offline
Faraday Member
**
Karma: 59
Posts: 3056
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sind doch alles Zahlen, oder ?

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

Code:
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 smiley-wink

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

Offline Offline
Sr. Member
****
Karma: 3
Posts: 385
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
//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:
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
Logged

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

Offline Offline
Sr. Member
****
Karma: 3
Posts: 385
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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

« Last Edit: August 31, 2012, 09:52:43 am by hk007 » Logged

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

0
Offline Offline
Faraday Member
**
Karma: 24
Posts: 3487
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink
Logged

Check out my experiments http://blog.blinkenlight.net

Germany
Offline Offline
Faraday Member
**
Karma: 59
Posts: 3056
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink
Logged

Offline Offline
Sr. Member
****
Karma: 3
Posts: 385
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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



Logged

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

0
Offline Offline
Faraday Member
**
Karma: 24
Posts: 3487
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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

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

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

und weiterhin max_fractional_digits auf 0 setzen.
Logged

Check out my experiments http://blog.blinkenlight.net

Pages: [1]   Go Up
Jump to: