Strtok with different delimiters

hi there I am planning to split a spring into pieces but there are mix of two delimiters..
The example of message is like " P,WE,PO, YI|UY,2" //notice there are 2 different delimiters

char buf[25];
 char messageType[2];
char sID[3];
char dID[3];
char route1[3];
char route2[3];
char routes[7];
char hops[2];


if (rf95.recv(buf, &len))
   {
      Serial.print("Received: ");
      Serial.println((char*)buf);
      strcpy (tempChars,buf);
      char * strtokIndx;
      strtokIndx = strtok (tempChars,",");
      strcpy (messageType,strtokIndx);

      strtokIndx = strtok (NULL,",");
      strcpy (sID,strtokIndx);

      strtokIndx = strtok (NULL,",");
      strcpy (dID,strtokIndx);
      

      strtokIndx = strtok (NULL,",");
      strcpy(routes,strtokIndx);
      if ((strtokIndx = strtok(NULL, "|" ))!=NULL);   // here is the part getting error
      {strcpy(route1,strtokIndx);
      strtokIndx = strtok(NULL, "|" );
      strcpy(route2,strtokIndx);}                

      strtokIndx = strtok (NULL,",");
      strcpy(hops,strtokIndx);

}

so I wanted to further split the route into route1 and route 2, but it is not compulsory to be there everytime.. that's why I am using if statement

the error I got is
cannot convert 'bool' to 'char*' in assignment

Thanks for helping me out in advanced!

if ((strtokIndx = strtok(NULL, "|" ))!=NULL);   // here is the part getting error

-->

strtokIndx = strtok(NULL, "|" );
if ((strtokIndx  !=NULL) 
{

Watch closely!

sry but do you mind to explain what is the mistake??

1 Like

I spotted two. Simple one: the ";" at the end of your if statement. Larger one: using an assignment function ("strtokIndx = ...") as part of an if condition. I didn't look for additional problems; there may be some.

Look at it this way; the compiler runs into something like this, would it make sense to you?
if ((x = 3) != NULL)

Ya.. I think tat was the prob, but I need to check if there is "|" in between the route, so that I can split them into two if there is... first mistake I have corrected.. tq.. then do you mind to share what should be the correct one?

this is totally legit.

an assignment statement's value is the value being assigned so it's perfectly legit to compare that value with something and you get a boolean which is what's needed for a condition in an if statement.

The true issue was the semi-colon after the if (condition) which was basically an empty statement to be executed if the condition was true.

still same error after I remove the semicolon..

Hm, OK, I thought it would evaluate to a boolean by default.

the end result is a boolean.

assume we write if ((x = 3) != 7) {...}

the compiler recognizes an if statement, it expects a truth value to result in the evaluation of what is within the parenthesis

in the parenthesis we have a conditional statement, that's good because a conditional statement evaluation is a truth value

so the compiler goes to evaluate the left side of the condition.
it performs x = 3which is an assignment statement. The evaluation (the returned value if you want) of this statement is the value being assigned. so x = 3is evaluated as 3

then the right side is evaluated, it's trivial since it's just a value 7

so the compiler ends up evaluating (3 != 7) which is true.

It's not considered good practice to write it this way though, so would not recommend it.

Stéphanie, as in other post, you only share snippets (Snippets R Us!)...
are you sure you have enough space in tempChars for example ?
(best to use nullptr in C++ by the way)

Yeah I understand that. But I was under the impression that an assignment operation would by default evaluate as a boolean immediately when used in an if-statement. My bad.

We can agree on that :wink:

yup..enuf space.. still same error even after I assign bigger bytes for tat..

if you have a space in front of the P, then you need 3 bytes to store messageType
you are also looking twice for a | but there is only one.

there is no space..

ohh because I thought of first one is for if statement, for checking if there is any "|" in between .

the use strstr() or strchr()

you seem to have various possibilities is it "P,WE,PO,YI|UY,2" or " P,WE,PO,YI,2" ?

yup, that's why need to check if "|" exists before further process

consider something like this then

char buf1[] = "P,WE,PO,YI|UY,2";
char buf2[] = "P,WE,PO,YI,2";

char messageType[2];
char sID[3];
char dID[3];
char route1[3];
char route2[3];
char routes[7];
char hops[2];

void parseBuffer(const char * payload) {
  char tempChars[100];
  char * strtokIndx;

  Serial.print("\nParsing: ");  Serial.println(payload);
  strlcpy (tempChars, payload, sizeof tempChars);

  if (strchr(tempChars, '|') != NULL) {    // multi route
    Serial.println("Multi Route");
    strtokIndx = strtok (tempChars, ",");
    strlcpy (messageType, strtokIndx, sizeof messageType);
    Serial.println(messageType);

    strtokIndx = strtok (NULL, ",");
    strlcpy (sID, strtokIndx, sizeof sID);
    Serial.println(sID);

    strtokIndx = strtok (NULL, ",");
    strlcpy (dID, strtokIndx, sizeof dID);
    Serial.println(dID);

    strtokIndx = strtok(NULL, "|" );
    strlcpy(route1, strtokIndx, sizeof route1);
    Serial.println(route1);

    strtokIndx = strtok(NULL, "," );
    strlcpy(route2, strtokIndx, sizeof route2);
    Serial.println(route2);
    
    strtokIndx = strtok (NULL, ",");
    strlcpy(hops, strtokIndx, sizeof hops);
    Serial.println(hops);
  } else {
    // single route
    Serial.println("Single Route");
    strtokIndx = strtok (tempChars, ",");
    strlcpy (messageType, strtokIndx, sizeof messageType);
    Serial.println(messageType);

    strtokIndx = strtok (NULL, ",");
    strlcpy (sID, strtokIndx, sizeof sID);
    Serial.println(sID);

    strtokIndx = strtok (NULL, ",");
    strlcpy (dID, strtokIndx, sizeof dID);
    Serial.println(dID);

    strtokIndx = strtok (NULL, ",");
    strlcpy(routes, strtokIndx, sizeof routes);
    Serial.println(routes);

    strtokIndx = strtok (NULL, ",");
    strlcpy(hops, strtokIndx, sizeof hops);
    Serial.println(hops);
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial);

  parseBuffer(buf1);
  parseBuffer(buf2);
}

void loop() {}

(that's what we mean by self contained code that can be compiled and tested versus snippets)

Serial Monitor (@ 115200 bauds) will show

Parsing: P,WE,PO,YI|UY,2
Multi Route
P
WE
PO
YI
UY
2

Parsing: P,WE,PO,YI,2
Single Route
P
WE
PO
YI
2

note also the use of strlcpy() to ensure you won't overflow your buffers in case of wrong input. of course it would help to check strtokIndx before doing the copy. (code needs to be hardened a bit)

1 Like

this example is just given for showing the structure of the data, it is actually unknown until I received it.. so the code is still applicable right?

of course, the parse() function will work as long as the parameter is exactly matching one of the two format.

That's the best way to test your code while developing. Fine tune your data processing in a small sketch aside working on static data and then once it works, you put the function into your real project.

That lets you deal with one problem at a time. Divide et impera as Roman used to say :slight_smile: