How does one split a string into more than only 2 values

Hi would like to continue with a topic that i see that has not really being answered.

I have come to the same problem i want to split the String in the for loop. I do see that other method has being promoted in the above link, like using the char *ptr = strtok(str, delim); But that i would not know how to implement it , as this line of code i'm using now seems to work for me for the two substrings.

But how ever this is were i would like to know, what would i add to the last three substrings to make it work. If you see the first two will work (0 , i) (i + 1) but the last three in there brackets how would i reconstruct it. If i can get help on it please.

    for (int i = 0; i < str_out.length(); i++ ) {
      if (str_out.substring(i, i + 1) == ",") {
        str_Ctemp1 = str_out.substring(0, i);
        str_Ftemp1 = str_out.substring(i + 1);// I got lost from here on down up to but limited by break;
        str_Ctemp2 = str_out.substring(1, i);   // Definitely wrong...
        str_Ftemp2 = str_out.substring(i + i);  // Definitely wrong...
        str_humid = str_out.substring(2, i);     // Definitely wrong...

The reason you didnt find solution in the other thread is because you want to stay with String. Ditch String, learn to use strtok.

You could have a look at the textparser library.

Example:

TextParser parser(",");
int Ctemp1, Ftemp1, Ctemp2, Ftemp2, humid;
parser.parseLine(str_out.c_str(), Ctemp1, Ftemp1, Ctemp2, Ftemp2, humid);

If you want to do it yourself, you could have a look at the strtol function (for C strings) or a combination of indexOf and substring if you want to stick to the String data type.

Thank you jfjaros for more of a positive approach and answer. Im not a programmer, so it takes time for me to work it out. I will go and take a look at it. my code is below so i would have to take out the for loop and somehow use the txtparser.

type or //Receicer and potesimeter
#include<RH_ASK.h>
#include<SPI.h>
const int Led = 8;
const int Led1 = 7;

static unsigned long printmillis = 0;

String str_receive;                 //Strings to Store Value
String str_Pwm_1;
String str_Pwm_2;
String str_distance;

RH_ASK rf_driver(2000, 11, 12);

void setup() {
  
Serial.begin(9600);
rf_driver.init();
pinMode(Led, OUTPUT);
pinMode(Led1, OUTPUT);

digitalWrite(Led, LOW);
digitalWrite(Led1, LOW);
}

void loop() {
 
    uint8_t buf[10];                       
    uint8_t buflen = sizeof(buf);
    if (rf_driver.recv(buf, &buflen)){
      
      str_receive = String((char*)buf);
      
      // Split string into two values
      for (int i = 0; i < str_receive.length(); i++) {
      if (str_receive.substring(i, i+2) == ",") {
      str_Pwm_1 = str_receive.substring(0, i);
      str_Pwm_2 = str_receive.substring(i+1);
      str_distance = str_receive.substring(i+2);
      break;
    
    }
   }

      char Pwm_1_string[4];
      char Pwm_2_string[4];
      char distancestring[6];

      str_distance.toCharArray(distancestring,6);              //Convert String into Char Array
      str_Pwm_1.toCharArray(Pwm_1_string,4);
      str_Pwm_2.toCharArray(Pwm_1_string,4);

      float distance = atoi(distancestring);                    //Convery Array into integer value
      int setPoint1 = atoi(Pwm_1_string);
      int setPoint2 = atoi(Pwm_2_string);

    if(distance < setPoint1){

    digitalWrite(Led, 1);
    delay(30);
    digitalWrite(Led, 0);
    delay(30);
    }

      if(millis() - printmillis >= 300UL) {
      Serial.print(setPoint1); 
      Serial.print("  SetPoint1: ");

      Serial.print(setPoint2); 
      Serial.print("  SetPoint2: ");
                                   //Display number value at LCD display
      Serial.print(distance);
      Serial.println(" cm Receiver Distance");
      printmillis = millis();
  }
  }
} code here

are you sure you are getting a trailing null char with the payload ?

I would also recommend not to go to the String class (memory duplication etc) but if you want to stay with the String class, you could iterate for as long as you are finding commas in the incoming String.

Maybe this will help you getting started.

#include <SPI.h>

#include <RH_ASK.h>
#include <textparser.h>

const int Led = 8;
const int Led1 = 7;
static unsigned long printmillis = 0;

RH_ASK rf_driver(2000, 11, 12);
TextParser parser(",");

void setup() {
  Serial.begin(9600);
  rf_driver.init();
  pinMode(Led, OUTPUT);
  pinMode(Led1, OUTPUT);
  digitalWrite(Led, LOW);
  digitalWrite(Led1, LOW);
}

void loop() {
  uint8_t buf[10];                       
  uint8_t buflen = sizeof(buf);
  if (rf_driver.recv(buf, &buflen)){
    char buf_[sizeof(buf)];
    memcpy(buf_, buf, sizeof(buf));

    char Pwm_1_string[4];
    char Pwm_2_string[4];
    float distance;
    int setPoint1;
    int setPoint2;
    parser.parseLine(
      buf_, Pwm_1_string, Pwm_2_string, distance, setPoint1, setPoint2);

    if (distance < setPoint1) {
      digitalWrite(Led, 1);
      delay(30);
      digitalWrite(Led, 0);
      delay(30);
    }

    if (millis() - printmillis >= 300UL) {
      Serial.print(setPoint1); 
      Serial.print("  SetPoint1: ");

      Serial.print(setPoint2); 
      Serial.print("  SetPoint2: ");
      //Display number value at LCD display
      Serial.print(distance);
      Serial.println(" cm Receiver Distance");
      printmillis = millis();
    }
  }
}

Disclaimer: untested code.

Thank you Jfjlaros will give it a go.

something like this if you want to stick to Strings

String fakePayload1 = "12,34,567,89,1011,12,131415";
String fakePayload2 = "999";
String fakePayload3 = "";
String fakePayload4 = ",,,3";

void extractData(String & message) {
  String extraction;
  int startPos = 0;
  int length;

  Serial.print(F("\nAnalysing [")); Serial.print(message); Serial.println(F("]"));

  do {
    length = message.substring(startPos).indexOf(',');
    if (length >= 0) {
      extraction = message.substring(startPos, startPos + length);
      startPos = startPos + length + 1;
    } else {
      extraction = message.substring(startPos);
    }
    Serial.print(F("extracted : [")); Serial.print(extraction); Serial.println(F("]"));
  } while (length >= 0);
}

void setup() {
  Serial.begin(115200); Serial.println();
  extractData(fakePayload1);
  extractData(fakePayload2);
  extractData(fakePayload3);
  extractData(fakePayload4);
}

void loop() {}

Serial Monitor (@ 115200 bauds) will show

Analysing [12,34,567,89,1011,12,131415]
extracted : [12]
extracted : [34]
extracted : [567]
extracted : [89]
extracted : [1011]
extracted : [12]
extracted : [131415]

Analysing [999]
extracted : [999]

Analysing []
extracted : []

Analysing [,,,3]
extracted : []
extracted : []
extracted : []
extracted : [3]

(would work with anything in between commas, not just numbers)

Ahaha, my approach was negative? You will thank me one day, that is if you decide to write own code and not scavenge forums for ready solutions

1 Like

I was under the impression this forum was to help guys like myself and not be as sarcastic in your first approach. I asked nicely. If you were in my world in my trade I would almost spoon feed you with knowledge. The code I posted was plenty research from my side, and I did try before I asked. I was extremely reluctant for two weeks before asking because I know I would get feed back like yours. I don’t have another 5 years to become Gods gift to coding.

Sorry, if you dont mind me asking. I want to know how would you put the extracted value into a variable. example: fakePayload1="12,34,567"
you would get :
extracted: [12]
extracted: [34]
extracted: [567]

how would I make it so that those 12,34,567 put into a variable. example:
a=12
b=34
c=567

so that I can use them for other uses?
Thank you very much!

you could store them in an array of Strings as they are being extracted

Looking at your sketch in post #4, it seems that you do not only want to extract the variables as strings, but you want to convert them to the appropriate type too:

  1. The buffer of type uint8_t is converted to a String.
  2. The String is split.
  3. The resulting parts are converted to char arrays.
  4. The char arrays are converted to float, int, etc.

In post #6, a method is given that does the following:

  1. The buffer of type uint8_t is converted to a char array.
  2. The variables (float, int, etc.) are extracted from the char array directly.

I wonder what you think is still missing in this approach.

Thanks for the recommendation and the time for replying me. However, I found the solution needed to solve my problem in a different site. You can check the solution here. Again, thank you very much. I hope it helps other people too!

Hi JfjLaros. I apologise for not getting back to you sooner, was off the site for a few days. And thank you again for your interest and your library. Yes what you are saying is correct about the conversions, I see that your library does the following. I have run you code that you have posted and this is what i am getting.
The Distance is correct reading i'm just getting nothing on the setpoints to read and to trigger the LED's maybe because i may have to do another conversion.

//Transmitter and potesiometer
#include<RH_ASK.h>
#include<SPI.h>

RH_ASK rf_driver(2000, 11, 12);

//const int Led = 8;
const int trig = 2;
const int echo = 3;
const int potPin_1  = A0;
const int potPin_2  = A1;

int MaxDis1 = 50;
int MinDis1 = 15;

int MaxDis2 = 150;
int MinDis2 = 50;

int range = 0;

String Trans_pwm_1;
String Trans_pwm_2;
String Trans_distance;
String Transmit;

static unsigned long printmillis = 0;

void setup() {
  
Serial.begin(9600);
rf_driver.init();

pinMode(trig, OUTPUT);
pinMode(echo, INPUT);
pinMode(potPin_1, INPUT);
pinMode(potPin_2, INPUT);

}

void loop() {
  long duration; 
  float distance;        // Long duration asignes the distance varable.
  digitalWrite(trig, LOW);
  delayMicroseconds(2);     //2000
  digitalWrite(trig, HIGH);
  delayMicroseconds(12);   //14
  digitalWrite(trig, LOW);
  //delayMicroseconds(10);

  duration = pulseIn(echo, HIGH);
  //distance = (duration/2) / 29.1; // Divided by the speed of sound
  distance = (duration / 2.0) * 0.0343;    //0.343 is mm and 0.0343 is cm
  //return distance;
  
  //range = getRangeFromSensor();
  int setPoint1 = map(analogRead(potPin_1), 0, 1024, MinDis1, MaxDis1);
  int setPoint2 = map(analogRead(potPin_2), 0, 1024, MinDis2, MaxDis2);
  

  Trans_pwm_1 = String(setPoint1);
  Trans_pwm_2 = String(setPoint2);
  Trans_distance = String(distance);
  Transmit = Trans_pwm_1 +","+Trans_pwm_2 +","+Trans_distance;
    
  const char *msg = Transmit.c_str();   // Converts const char to String
  rf_driver.send((uint8_t *)msg,strlen(msg)); // Sends the String
  rf_driver.waitPacketSent();
  
  
  if(millis() - printmillis >= 300UL) {   // Serial print refresh  // Umcomment if need
  Serial.print("Transmitter Distance cm  ");
  Serial.println(distance);

  Serial.print("Set 1: ");
  Serial.println(setPoint1);

  Serial.print("Set 2: ");
  Serial.println(setPoint2);

  Serial.println("");
  //delay(300);
  printmillis = millis();
  }
 }

Screenshot 2022-10-21 at 1.28.13 PM

Your modified code

#include <SPI.h>

#include <RH_ASK.h>
#include <textparser.h>

const int Led = A0;
const int Led1 = A1;

static unsigned long printmillis = 0;

RH_ASK rf_driver(2000, 11, 12);
TextParser parser(",");

void setup() {
  Serial.begin(9600);
  rf_driver.init();
  pinMode(Led, OUTPUT);
  pinMode(Led1, OUTPUT);
  digitalWrite(Led, LOW);
  digitalWrite(Led1, LOW);
}

void loop() {
  uint8_t buf[32];                       
  uint8_t buflen = sizeof(buf);
  if (rf_driver.recv(buf, &buflen)){
    char buf_[sizeof(buf)];
    memcpy(buf_, buf, sizeof(buf));

    char Pwm_1_string[4];
    char Pwm_2_string[4];
    int distance;
    int setPoint1;
    int setPoint2;
    parser.parseLine(buf_,Pwm_1_string, Pwm_2_string, distance, setPoint1, setPoint2);

    if (distance <= setPoint1 && distance >= 10) {
      digitalWrite(Led, 1);
      delay(30);
      digitalWrite(Led, 0);
      delay(30);
    } 
    //if((distance < setPoint1) && (distance > setPoint2)){
      //digitalWrite(Led1, 1);
      //delay(30);
      //digitalWrite(Led1, 0);
      //delay(30);
    //}

    if (millis() - printmillis >= 300UL) {
      
  Serial.print("Receiver Distance cm  ");
  Serial.println(distance);

  Serial.print("Set 1: ");
  Serial.println(setPoint1);

  Serial.print("Set 2: ");
  Serial.println(setPoint2);

  Serial.println("");
      printmillis = millis();
    }
  }
}

Screenshot 2022-10-21 at 2.11.10 PM

Can you print the content of the buffer and share the output with us?

Hope this is what you are looking for.
Screenshot 2022-10-21 at 8.57.49 PM

Do I understand correctly that you only want to extract three values per line: two integers and one floating point number?

If so, the following lines should set setPoint1 to 27, setPoint2 to 111 and distance to 12.551 for the last example you gave.

int setPoint1;
int setPoint2;
float distance;
parser.parseLine(buf_, setPoint1, setPoint2, distance);

Ya the values will be three or what the ultrasonic sensor can put out in cm or what i have set it to in the transmitter max and min settings. And the two integers and the floating point

Thank you jfjlaros, your (parser.parseLine) library works like a charm. And it works as advertised. Getting my Setpoint readings and able to blink the LED as well with the setpoint. Thanks again. Now i need to add to the code, and refine it.

Code after changes.

#include <SPI.h>

#include <RH_ASK.h>
#include <textparser.h>

const int Led = A0;
const int Led1 = A1;

static unsigned long printmillis = 0;

RH_ASK rf_driver(2000, 11, 12);
TextParser parser(",");

void setup() {
  Serial.begin(9600);
  rf_driver.init();
  pinMode(Led, OUTPUT);
  pinMode(Led1, OUTPUT);
  digitalWrite(Led, LOW);
  digitalWrite(Led1, LOW);
}

void loop() {
  uint8_t buf[32];                       
  uint8_t buflen = sizeof(buf);
  if (rf_driver.recv(buf, &buflen)){
    char buf_[sizeof(buf)];
    memcpy(buf_, buf, sizeof(buf));

    //char Pwm_1_string[4];
    //char Pwm_2_string[4];
    float distance;
    int setPoint1;
    int setPoint2;
    //parser.parseLine(buf_,Pwm_1_string, Pwm_2_string, distance, setPoint1, setPoint2);
    parser.parseLine(buf_, setPoint1, setPoint2, distance);

    if (distance <= setPoint1 && distance >= 10) {
      digitalWrite(Led, 1);
      delay(30);
      digitalWrite(Led, 0);
      delay(30);
    } 
    //if((distance < setPoint1) && (distance > setPoint2)){
      //digitalWrite(Led1, 1);
      //delay(30);
      //digitalWrite(Led1, 0);
      //delay(30);
    //}

    if (millis() - printmillis >= 300UL) {
      
  Serial.print("Receiver Distance cm  ");
  Serial.println(distance);

  Serial.print("Set 1: ");
  Serial.println(setPoint1);

  Serial.print("Set 2: ");
  Serial.println(setPoint2);

  //Serial.print("Buf. ");
  //Serial.println(buf_);

  Serial.println("");
      printmillis = millis();
    }
  }
}

Screenshot 2022-10-23 at 11.36.48 AM