[C] Einfacher Parser

Xile

Lieutenant
Registriert
Jan. 2007
Beiträge
557
Hallo zusammen,

ich hab da ein kleines Problem:

Ich habe Datensätze der Form 11;22;33;44;55 die ich nach dem Trennzeichen ; in Einzelstrings zerlegen will, also:

String1 = 11
String2 = 22
String3 = 33
String4 = 44
String5 = 55

An sich nicht schwer, jedoch kann es vorkommen das ein Bereich des Datensatzen NULL (oder leerer String) ist, d.h. der Eingangsdatensatz könnte auch folgendermaßen aussehen:

11;22;;44;55

das Ganze sollte dann so zerlegt werden:

String1 = 11
String2 = 22
String3 = (leerer String)
String4 = 44
String5 = 55

Ich habe das Ganze nun schon mit dem StringTokenizer und sscanf versucht, leider ohne Erfolg. Der StringTokenizer behandelt zwei oder mehr aufeinanderfolgende Trennzeichen als ein Trennzeichen, somit gehen mit Datenbereiche verloren und mit sscanf klappt es auch nicht... wenn man folgendermaßen Zerlegen will:

Code:
char *dataset = "11;22;;44;55";
int result;

char i[10], j[10], k[10], l[10], m[10];

int main()
{
result = sscanf(dataset, "%[^';'];%[^';'];%[^';'];%[^';'];%[^';']",i,j,k,l,m);

}

Hat jemand eine Idee wie man den String zerlegen kann, sodass auch leere Datenfelder (zwei aufeinanderfolgende Semikolons) erhalten beliben. Maximale Länge der einzelenen Datenfelder ist fix und bekannt!

Danke im Voraus!
 
Dann suche doch einfach die Position des Trennzeichens und nimmst die Zeichen 0 bis Pos.
Dann suchst du ab Pos die nächste Position des Trennzeichens und nimmst die Zeichen Pos+1 bis NeuePos. Usw....
 
ungetesteter code, aber sowas in die Richtung könnte gehen:
Code:
int index = 0;
int currentStart = 0;
int currentNr = 0;
while (dataset[index] != 0) {
  if (dataset[index] == ';') {
    if (currentStart > index) {
      dataset[index] = 0;  // Ende markieren
      sscanf(dataset[currentStart], "%d", &values[currentNr]);
      dataset[index] = ';';  // Rücksetzen
    } else {
      values[currentNr] = 0;  // kein Eintrag
    }
    currentStart = index + 1;
    currentNr++;
  }   
  index = index + 1;
}

Edit: ist im Grunde das, was wahli auch meint

Edit: oh, ich sehe gerade, ich mach da immer int-Werte draus...
das ist ja noch einfacher so (targetStrings als mehrdimensionales Array halt):
Code:
int index = 0;
int targetIndex = 0;
int targetNr = 0;
while (dataset[index] != 0) {
  if (dataset[index] != ';') {
    targetStrings[targetNr][targetIndex] = dataSet[index];
    targetIndex = targetIndex + 1;
  } else {
    targetStrings[targetNr][targetIndex] = 0;  // Ende markieren
    targetNr = targetNr + 1;
    targetIndex = 0;
  }   
  index = index + 1;
}
 
Zuletzt bearbeitet:
Die Position des ersten ; könnte man mit strchr() ermitteln, wie ermittelt man die Position den zweiten ; ? Dafür müsste ich der Suchfunktion einen Index mitgeben ab dem er Suchen soll!!???
 
Oder einfach den String manuell durchlaufen und bauen ... soll ja auch möglich sein...
Oder einfach den Teil des Strings angeben, der das vorherige Semikolon nicht enthält - die Position ist ja schließlich bekannt...

C-Strings sind in der Hinsicht etwas extrem flexibles...
strchr(&cstring[5], ';')
strchr(cstring + 5, ';')
sucht z.B. im Teilstring ab dem 6. Zeichen bis zum Ende... ergo werden bei einer Suche dann die ersten 5 Zeichen nicht betrachtet, müsste man beim Ergebnis aber mitbetrachten...
 
Zuletzt bearbeitet:
Würde wohl gehen, allerdings möchste ich Schleifen vermeiden, da der Code in einem Prozessleitsystem abläuft und alle 200ms zyklisch ausgeführt wird.
 
Ich sehe keinen Zusammenhang zwischen Schleifen und Prozessleitsystem / zyklische Aufrufe / performancekritischen Code. Ich kann mir sogar vorstellen, dass dieser Code schneller läuft als sscanf. Warum? sscanf ist eine eierlegende Wollmilchsau (die intern sicherlich auch irgendeine Form von Schleifen nutzt...). Der kannst du alles übergeben. Der zweite Algorithmus ist genau für seine Aufgabe geschrieben. Kannst ja mal Untersuchungen machen, was schneller ist - und dabei wirst du merken, dass bei einem Aufruf die Laufzeit von keinem messbar sein wird... da interessiert es auch nicht, dass das Ding 5 Mal in einer Sekunde aufgerufen wird... das ist ja quasi nie.

Edit:
Code:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

char *dataset = "11;22;;44;55";
char targetStrings[10][10];

void reset()
{
	for (int i = 0; i < 10; i++) targetStrings[i][0] = 0;
}

void printresult()
{
	for (int i = 0; i < 10; i++) {
		if (targetStrings[i][0] == 0) {
			continue;
		}
		printf("%d: %s\n", i, targetStrings[i]);
	}
}

void one()
{
	sscanf(dataset, "%[^';'];%[^';'];%[^';'];%[^';'];%[^';']", targetStrings[0], targetStrings[1], targetStrings[2], targetStrings[3], targetStrings[4]);
}

void two()
{
	int index = 0;
	int targetIndex = 0;
	int targetNr = 0;
	while (dataset[index] != 0) {
	  if (dataset[index] != ';') {
		targetStrings[targetNr][targetIndex] = dataset[index];
		targetIndex = targetIndex + 1;
	  } else {
		targetStrings[targetNr][targetIndex] = 0;  // Ende markieren
		targetNr = targetNr + 1;
		targetIndex = 0;
	  }   
	  index = index + 1;
	}
}


int main() 
{
	clock_t start, end;
	const int count = 100000;

	for (int j = 0; j < 5; j++) {
		reset();
		start = clock();
		for (int i = 0; i < count; i++) {
			one();
		}
		end = clock();
		printf("Time sscanf: %f\n",  (double)(end-start)/ CLOCKS_PER_SEC);

		reset();
		start = clock();
		for (int i = 0; i < count; i++) {
			two();
		}
		end = clock();
		printf("Time evil loop: %f\n",  (double)(end-start)/ CLOCKS_PER_SEC);
	}
	system("pause");
}

Einfach das mal anschauen ...
 
Zuletzt bearbeitet:
Besten Dank für den Code, habe das ganze jetzt mit einer Schleife gelöst!
 
Zurück
Oben