PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : String am AVR parsen und zerlegen



n0Br4iN3r
08.11.2005, 18:58
Hallo,
ich hab da mal eine Frage: Würde euch ein möglichst einfacher und schlanker Code für das parsen und zerlegen eines Strings den ich über USART empfange einfallen? In der libc gäbs sogar ein strsep bzw. ein strtok_r, aus diesen beiden werde ich aber nicht schlau. Dann hab ich mir eine eigene Funktion geschrieben, die aber relativ umständlich ist und am AVR viel Speicher verbraucht.
Darum meine Frage an euch:
Ich sende per USART einen String, z.B. set time 12:00:00 oder get time oder help. Dann möchte ich den String in Teilstrings zerlegen, die durch Leerzeichen getrennt sind, die Anzahl der Argumente variiert jedoch. z.B. bei set time 12:00:00 hätte ich dann gerne 3 strings zu set, time und 12:00:00 (die Zeit verarbeite ich dann mit sscanf weiter). Oder beim Kommando help sollte nur in einem String eben help drin stehen. Die Abfrage kann man danach einfach mit strcmp machen.
Ich hoffe jemand von euch weiß eine vernünftige Methode, um den String zu zerlegen.

Danke und mfg n0Br4iN3r

SprinterSB
08.11.2005, 23:47
Im eigentlichen Sinn zerlegen würd ich das Ding gar nicht.

Eher angemessen scheint mir so was: Zeiger auf die Anfänge/Längen der einzelnen Teilstrings besorgen. Dadurch vermeidest du das rumkopieren des Strings und dynamisches Allokierung.

Etwa so:

char* getSubstring (char *str, char *length, unsigned char arg_no);

return-Wert ist der Zeiger auf den Anfang des Teilstrings, *length die Länge desselbigen und arg_no die Nummer des Teilstrings (hier mit 1 angefangen zu zählen, evtl ist 0 günstiger).

Beispiel: str="set time 12:00:00"
getSubstring (str, &len, 1) --> len=3, return = str
getSubstring (str, &len, 2) --> len=4, return = str+4
getSubstring (str, &len, 3) --> len=8, return = str+9
getSubstring (str, &len, 4) --> len=-1, return = NULL

Oder was Destriktives, wenn das nicht zu Problemen führt: Das ' ' nach set durch Stringende '\0' ersetzen. Aber erst nachdem du den Anfang des Folgestrings ab time irgendwo gemerkt hast (local static etwa). Womöglich machen die Tokenizer genau sowas.

sscanf() zieht wahrscheinlich einiges aus der libc bzw libgcc hinter sich her. Evtl den ganzen float-Klumbatsch, den du gar nicht brauchst. sprintf() ist auch super übel. Was alles dazugelinkt wird aus irgendwelchen Bibliotheken siehst du am Mapfile, das du beim Linken am besten immer mitgenerieren lässt.

n0Br4iN3r
09.11.2005, 19:42
Danke für die Antwort, werd ich gleich mal probieren.
mfg

SprinterSB
10.11.2005, 11:42
Wenn dein Zeit-String immer in dem Format ankommt, ist das umrechnen simpel. Daß das Format stimmt stellt dein 'Parser' sicher bzw der Sender.

Beispiel:
char *time;
time = "12:34:56";

uint8_t stunde, minute, sekunde;

stunde = 10*(time[0]-'0') + (time[1]-'0');
minute = 10*(time[3]-'0') + (time[4]-'0');
sekunde= 10*(time[6]-'0') + (time[7]-'0');

oder
stunde = my_atoi2 (time);
minute = my_atoi2 (time+3);
...
// Wandelt 2-stelligen Dezimal-String nach unsigned char
uint8_t my_atoi2 (char *str)
{
// ... evtl noch ein Test aufs Format
return 10*(str[0]-'0') + (str[1]-'0');
}


Den Klotz xscanf() und xprintf() brauchst du eigentlich nicht. Zwar bequem, vom Speicher- (RAM+Flash) und Zeitverbrauch her aber höllisch. Zumindest für Hänflinge wie AVR.