Explode a char[] array with a delimiter for IOT project

My goal is to process a string of characters received from my web server after submitting a request.
I’ve handled the sending and receiving the strings from the server just fine. now I need to parse the string into an array of information:
the following code is a segment of the overall code which is much larger.

char S = “a=this is a test,b=111,c=222,d=322.1,e=456,f=777,g=Hello World”;
This is an example of what the server could return.
I need to break the string up into an array of parts so I can evaluate them

PHP uses a function called explode(delimiter, Str) which returns an array pointing to strings of each piece. I am trying to reproduce this functionality. I haven’t found anything already made to do this for Arduino. If there is something already there PLEASE point me to it :slight_smile:

otherwise here is what i have…

void setup() {
        Serial.begin(115200);
}

void loop() {
        char S[] = "a=this is a test,b=111,c=222,d=322.1,e=456,f=777,g=Hello World";
      
        
        int i = 0,m = 0;
        char** a = explode(',',S); 
        m = sizeof(*a);
        Serial.println("trying to find the size of a as it is a pointer to an array");
 
        Serial.println(sizeof(a));
        Serial.println(sizeof(*a));
        Serial.println(sizeof(**a));
         m = sizeof(*a);
        for (i = 0; i < m; i++) { 
                 Serial.println(a[i]);
        }
        Serial.println("only returned 2 while the array has 7 elements for this instance!!!");
        for (i = 0; i < 7; i++) { 
                 Serial.println(a[i]);
        }      
        Serial.println("Sence Im using malloc and realloc i need to free up memory... my freeExplode, i'm afraid, isn't working correctly either.");       
        freeExplode(a);
        delay(10000);
}

// This example came from https://gist.github.com/kopiro/5237558 and seems to be working correctly for the most part.
char** explode(char delimiter, char* str) {
	int l = strlen(str), i=0, j=0, k=0;
	char x = NULL;
	char** r = (char**)realloc(r, sizeof(char**)); 
	r[0] = (char*)malloc(l*sizeof(char)); 
	while (i<l+1) {
		x = str[i++];
		if (x==delimiter || x=='\0') {
			r[j][k] = '\0';
			r[j] = (char*)realloc(r[j], k*sizeof(char));
			k = 0;
			r = (char**)realloc(r, (++j+1)*sizeof(char**));
			r[j] = (char*)malloc(l*sizeof(char));
		} else {
			r[j][k++] = x;
		}
	}
	return r;
}
void freeExplode(char** a){
        int i = 0,m = 0;
        m = sizeof(*a);
        for (i = 0; i < m; i++) { 
                free(a[i]);
        }
        free(a); 
}

Look up the strtok function. Here is a link strtok/

groundfungus: Look up the strtok function. Here is a link strtok/

I believe that will work wonders!!! I'm changing up my code to work with this strtok() function Thank you, Thank you!!!

After making changes Here is the final resulting code:

#include <stdio.h>
#include <string.h>
void setup() {
        Serial.begin(115200);
}

void loop() {
    char S[] = "a=this is a test,b=111,c=222,d=322.1,e=456,f=777,g=Hello World";
    ProcessString(",",S);
    delay(1000);
}

void ProcessString(char * delimiter, char* str){
    char * pch;
    pch = strtok (str,delimiter);
    while (pch != NULL){
        Serial.print(pch);
        Serial.print("\t\tKey:");
        Serial.print(pch[0]); //Single Char Key
        
        Serial.print("\tVal:");
        Serial.println(pch+2); // Skip the key and equal Sign
         Serial.println(""); 
       
        pch = strtok (NULL, ",");
    }   
}

again Thank you groundfungus for you quick response!!! this became easier than expected :slight_smile:

strtok() is destructive. Under the hood it uses strchr() and you can use that to do non-destrutive parsing if needed.

strtok() like this example:

struct MyMessage{
  char a[32];
  int b;
  int c;
  float d;
  int e;
  int f;
  char g[32];
};

char data[] = "a=this is a test,b=111,c=222,d=322.1,e=456,f=777,g=Hello World";
MyMessage myMessage;

void setup() 
{
  Serial.begin(9600);
  decodeMessage(data);
  Serial.println(myMessage.a);
  Serial.println(myMessage.b);
  Serial.println(myMessage.c);
  Serial.println(myMessage.d);
  Serial.println(myMessage.e);
  Serial.println(myMessage.f);
  Serial.println(myMessage.g);
}

void loop() 
{
  
}

void decodeMessage(char* messg)
{
  char buffer[64] = "";
  strcpy(buffer, messg);
  strtok(buffer, "=");
  strcpy(myMessage.a, strtok(NULL, ",="));
  strtok(NULL, "=");
  myMessage.b = atoi(strtok(NULL, ",="));
  strtok(NULL, "=");
  myMessage.c = atoi(strtok(NULL, ",="));
  strtok(NULL, "=");
  myMessage.d = atof(strtok(NULL, ",="));
  strtok(NULL, "=");
  myMessage.e = atoi(strtok(NULL, ",="));
  strtok(NULL, "=");
  myMessage.f = atoi(strtok(NULL, ",="));
  strtok(NULL, "=");
  strcpy(myMessage.g, strtok(NULL, ",="));
}

every message has to have every field...

Look at Nick Gammon's State Machine examples for other methods.

Thanks BulldogLowell, I like the structure idea it will also work well with the EEPROM routine i'm using to store the changes even after a power failure...

Im using the EEPROMex.h library and it will save restore structures to EEPROM

Thanks for all your help.

sterretje:
strtok() is destructive. Under the hood it uses strchr() and you can use that to do non-destrutive parsing if needed.

Most of the time, destructive is perfectly ok. This sketch clobbers the contents of the buffer to break it up into fragments, but “meh”. There’s no safety net, of course. That comes extra :slight_smile: .

struct kv {
  char *key;
  char *value;
};

void setup() {
  Serial.begin(57600);
  while (!Serial);
  Serial.println("Starting sketch");

  char S[] = "a=this is a test,b=111,c=222,d=322.1,e=456,f=777,g=Hello World";

  Serial.println("test data: ");
  Serial.println("(vertical bars are NUL \\0 characters)");
  for(int i = 0; i<sizeof(S); i++) {
    if(S[i])
    Serial.print(S[i]);
    else 
    Serial.print("|");
  }
  Serial.println();
  
  struct kv parsed[20]; // 20 is enough space for our input
  int nparsed = 0;

  for (char *p = strtok(S, ","); p; p = strtok(NULL, ","))
  {
    parsed[nparsed].key = p;
    p = strchr(p,'=');
    *p++ = '\0';
    parsed[nparsed].value = p;
    nparsed++;
  }

  Serial.print("parsed ");
  Serial.print(nparsed);
  Serial.println(" key/value pairs");
  
  for (int i = 0; i < nparsed; i++) {
    Serial.print("key: ");
    Serial.print(parsed[i].key);
    Serial.print(", value: ");
    Serial.print(parsed[i].value);
    Serial.println();
  }

  Serial.println("after the parse, our test buffer looks like this: ");
  Serial.println("(vertical bars are NUL \\0 characters)");
  for(int i = 0; i<sizeof(S); i++) {
    if(S[i])
    Serial.print(S[i]);
    else 
    Serial.print("|");
  }
  
  Serial.println();  
  Serial.println("Done.");  
}

void loop() {
}

Thanks PaulMurrayCbr, I'm satisfied with clobbering the received array of chars :) I need only the key and value pairs to allow me to store the changes for controlling my project. You code was incredibly helpful in allowing me to understand what strtok() does. Thanks!!! Everyone is so Helpful!

Z