Help needed for strtok function

Hello,

I need some help with the strtok function. I have a string with a label and 16 integers like theis :

Qs323=976;456;890;1000;24;876;0;432;0;1000;1000;989;745;0;876;5

I would like to split the string by extracting all the integers separated by semicoluns. The result will be :

integer1=976 integer2=456 .... integer16=5

I wrote a code like this :

equalPosition = rawIncomingString.indexOf('=');
                  variableLabel = rawIncomingString.substring(0, equalPosition);                  
                  trimIncomingString = rawIncomingString.substring(equalPosition+1, rawIncomingString.length());
                  rawIncomingString = "";
                        
                  semicolunPosition = trimIncomingString.indexOf(';');
                  integer1String = trimIncomingString.substring(0, semicolunPosition);
                  trimIncomingString = trimIncomingString.substring(semicolunPosition+1, trimIncomingString.length());
                  integer1 = integer1String.toInt();

The string incoming is named "rawIncomingString". The 2 first lines separate the label "Qh323" from the string and store it into variableLabel string. The 2 next lines build a new string named trimIncoming string witch looks like :

976;456;890;1000;24;876;0;432;0;1000;1000;989;745;0;876;5

The 4 next lines separate the first integer, convert to int and store into integer1 int.

My problem is that I need to repeat the operation 16 times. I think the strtok function will be more efficient but I don't know how to use it. Could somebody help me and send a piece of code with my example ? Thanks a lot

const int MAX_LEN = 80;
const char lineEnding = '\n'; // whatever marks the end of your input.
char inputSentence [MAX_LEN + 1];

const byte MAX_TOKENS = 4;
const char* delimiters = ", "; // whatever characters delimit your input string
char* tokens [MAX_TOKENS + 1];
...
...
...
    int tokenIndex = 0;
    Serial.println (inputSentence); 
    tokens [tokenIndex] = strtok (inputSentence, delimiters);
    while ((tokenIndex < MAX_TOKENS - 1) && tokens [tokenIndex])
    {
      tokens [++tokenIndex] = strtok (NULL, delimiters);
    }

Thank you. I don't see where is the output. My knowledge is very limited unfortunately. Could you adapt the code to my precise problem and explain a little bit more ? It would be very nice.

Here is the code I built for testing :

#include <Ethernet.h>
#include <SPI.h>

const int MAX_LEN = 80;
const char lineEnding = '\n'; // whatever marks the end of your input.
char inputSentence [MAX_LEN + 1];

const byte MAX_TOKENS = 4;
const char* delimiters = ";"; // whatever characters delimit your input string
char* tokens [MAX_TOKENS + 1];

byte mac[] = {  0x90, 0xA2, 0xDA, 0x0F, 0x19, 0x73 }; // MAC adress of the ethernet shield
byte IP [] = { 192,168,1,21 }; // IP Adress of the ethernet shield
byte server [] = { 192,168,1,20 }; // IP adress of PSX server
int serverPort=10748; // Port used by PSX server for data

String Qs323 = "Essai";

Client client (server, serverPort);

int equalPosition;
String rawIncomingString;
String trimIncomingString;
String variableLabel;

void setup()
{
Ethernet.begin(mac, IP); // Connecting to server
Serial.begin(9600);
}

void loop()
{
  if (client.connected())
    {
      if (client.available()) 
        {
          char c = client.read();
          rawIncomingString += c;
          if (c == '\n')
            {
              if (rawIncomingString.startsWith(Qs323))
                { 
                  equalPosition = rawIncomingString.indexOf('=');
                  variableLabel = rawIncomingString.substring(0, equalPosition);                  
                  trimIncomingString = rawIncomingString.substring(equalPosition+1, rawIncomingString.length());
                  rawIncomingString = "";
                  
                  int tokenIndex = 0;
                  Serial.println (trimIncomingString); 
                  tokens [tokenIndex] = strtok (trimIncomingString, delimiters);
                  while ((tokenIndex < MAX_TOKENS - 1) && tokens [tokenIndex])
                  {
                    tokens [++tokenIndex] = strtok (NULL, delimiters);
                  }
              
                  
                }
            }
        }
    }
}

The debugger says :

sketch_jul30a.cpp: In function ‘void loop()’:
sketch_jul30a:50: error: cannot convert ‘String’ to ‘char*’ for argument ‘1’ to ‘char* strtok(char*, const char*)’

What is wrong ?

What is wrong ?

cannot convert 'String' to 'char*' for argument '1' to 'char* strtok(char*, const char*)'

Dump String, use simple C strings

I'm lost. Could you be more precise for me please ?

This is a String String Qs323 = "Essai";

This is a string char* Qs323 = "Essai"; or char Qs323 [6] = "Essai";

Don't use String - they are not appropriate for memory-limited machines like the Arduino.

Understood, but if I declare strings like this, I don’t have to functions .startswith, substring, etc…

The error is now :

Essai_strtok.cpp: In function ‘void loop()’:
Essai_strtok:44: error: request for member ‘startsWith’ in ‘rawIncomingString’, which is of non-class type ‘char*’
Essai_strtok:46: error: request for member ‘indexOf’ in ‘rawIncomingString’, which is of non-class type ‘char*’
Essai_strtok:47: error: request for member ‘substring’ in ‘rawIncomingString’, which is of non-class type ‘char*’
Essai_strtok:48: error: request for member ‘substring’ in ‘rawIncomingString’, which is of non-class type ‘char*’

#include <Ethernet.h>
#include <SPI.h>

const int MAX_LEN = 80;
const char lineEnding = '\n'; // whatever marks the end of your input.
char inputSentence [MAX_LEN + 1];

const byte MAX_TOKENS = 4;
const char* delimiters = ";"; // whatever characters delimit your input string
char* tokens [MAX_TOKENS + 1];



byte mac[] = {  0x90, 0xA2, 0xDA, 0x0F, 0x19, 0x73 }; // MAC adress of the ethernet shield
byte IP [] = { 192,168,1,21 }; // IP Adress of the ethernet shield
byte server [] = { 192,168,1,20 }; // IP adress of PSX server
int serverPort=10748; // Port used by PSX server for data

String Qs323 = "Essai";

Client client (server, serverPort);

int equalPosition;
char* rawIncomingString;
char* trimIncomingString;
char* variableLabel;


void setup()
{
Ethernet.begin(mac, IP); // Connecting to server
Serial.begin(9600);
}

void loop()
{
  if (client.connected())
    {
      if (client.available()) 
        {
          char c = client.read();
          rawIncomingString += c;
          if (c == '\n')
            {              
              if (rawIncomingString.startsWith(Qs323))
                { 
                  equalPosition = rawIncomingString.indexOf('=');
                  variableLabel = rawIncomingString.substring(0, equalPosition);                  
                  trimIncomingString = rawIncomingString.substring(equalPosition+1, rawIncomingString.length());
                  rawIncomingString = "";
                  
                  int tokenIndex = 0;
                  Serial.println (trimIncomingString); 
                  tokens [tokenIndex] = strtok (trimIncomingString, delimiters);
                  while ((tokenIndex < MAX_TOKENS - 1) && tokens [tokenIndex])
                  {
                    tokens [++tokenIndex] = strtok (NULL, delimiters);
                  }
              
                  
                }
            }
        }
    }
}

No, but you've got a different family of functions like "strstr", "strchr" etc.

Thank you very much !

I cannot adapt to my project as described. If somebody can take time to rewrite it it would be so nice. My knowledge is very limited but I need this.

This may help explain what AWOL was trying to tell you:

char message[] = "Qs323=976;456;890;1000;24;876;0;432;0;1000;1000;989;745;0;876;5";
const byte MAX_TOKENS = 20;
const char* delimiters = ",;="; // whatever characters delimit your input string
char* tokens [MAX_TOKENS + 1];
void setup() {
  // put your setup code here; to run once:
    int tokenIndex = 0;
    Serial.begin(115200);
    Serial.println (message); 
    tokens [tokenIndex] = strtok (message, delimiters);
    while ((tokenIndex < MAX_TOKENS - 1) && tokens [tokenIndex])
    {
      tokens [++tokenIndex] = strtok (NULL, delimiters);
    }
    for (int i = 0; i < tokenIndex; i++)
    Serial.println(tokens[i]);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Thank you very much for all. My message come from Ethernet server and I first need to put out the "Qh=" then split all values into separate integers. The message comes also many times with different values and I need to repeat every time. Examples you give me are always from static message.

Examples you give me are always from static message.

You just need to apply the same method to your dynamic messages.

Believe me, I try from 3 hours already...

But we can't see your code, so we can't really help.

Ok ! After about 6 hours to do something many of you would have done within 15 minutes, I adapted the pieces of code you gave me to my usage (dynamic chars comming from network, Qs323 detection, split and store into integers). I want to thank you for your big help and patience. I adapted also fo debugging with serial communication replacing Ethernet. My last problem is about the char array named : rawIncomingCharArray which stores the incoming chars and test them to know if the message received begins with “Qs323”. The problem is that I want to clear this array after every loop, Qs323 detected or not, in order to have a new fresh empty array ready for new incoming chars and testing. I tried memset(rawIncomingCharArray, 0, 80); but the Arduino freezes after the first loop. A last help will be appreciated. Here is my code :

#include <Ethernet.h>
#include <SPI.h>

const byte MAX_TOKENS = 8;
const char* delimiters = "=;"; // Whatever characters delimit your input string
char* tokens [MAX_TOKENS + 1];

byte index = 0;
char rawIncomingCharArray[80];
int integer1;
int integer2;

byte mac[] = {  0x90, 0xA2, 0xDA, 0x0F, 0x19, 0x73 }; // MAC adress of the ethernet shield
byte IP [] = { 192,168,1,21 }; // IP Adress of the ethernet shield
byte server [] = { 192,168,1,20 }; // IP adress of PSX server
int serverPort=10748; // Port used by PSX server for data

//Client client (server, serverPort);

void setup()
{
//Ethernet.begin(mac, IP); // Connecting to server
Serial.begin(9600);
}

void loop()
{
  //if (client.connected())
    //{
        if (Serial.available()) // CHANGE FOR CLIENT
          {
            char c = Serial.read(); // CHANGE FOR CLIENT
            rawIncomingCharArray[index++] = c;          
            if (c == ' ') // REPLACE WITH '\n'
              {              
                Serial.println(rawIncomingCharArray);              
                if (strstr(rawIncomingCharArray, "Qs323"))
                  { 
                    Serial.println("Qs323 detected");                 
   
                    int tokenIndex = 0;    
                    Serial.println (rawIncomingCharArray); 
                    tokens [tokenIndex] = strtok (rawIncomingCharArray, delimiters);
                    while ((tokenIndex < MAX_TOKENS - 1) && tokens [tokenIndex])
                    {
                      tokens [++tokenIndex] = strtok (NULL, delimiters);
                      integer1 = atoi(tokens[1]);                    
                      integer2 = atoi(tokens[2]);                    
                    }
                                      
                    Serial.println(integer1);
                    Serial.println(integer2);               
                    
                  }               
              }
          }
    //}
}

Every time you read a character and buffer it in the array, you must write a zero to the next location in the array.
When you’ve finished processing the string, simply reset the array index, and write a zero to the first location in the buffer.

Any example ? It's not very clear for me, sorry again.

char c = Serial.read(); // CHANGE FOR CLIENT
rawIncomingCharArray[index++] = c;
rawIncomingCharArray[index] = '\0';

Every time you read a character and buffer it in the array, you must write a zero to the next location in the array.