Split string

Hi - i’m getting strings from my serial looking like this : FL010100

I would like to split the string into part1:FL part2:01 part3:100 … I have looked at substring and array and can’t find out what’s best…

An other string could look like this : CF02L0125P01T00:00:08.556

The first part of the string FL or CF shows the “kind” of data i’m getting and the length of the string is always the same … FL is 8 characters and CF is 25 and so on …

What would you recommend?

How are the strings terminated?

All strings starts with [ and ends with ] ...

You can use strtok(), strcpy(), itoa() and so on.

char text[] = "CF02L0125P01T00:00:08.556";
// check if a substring matches a given string
if (strncmp(&text[0], "FL", 2) == 0) { // first two characters match "FL"
  // ...
} else if (strncmp(&text[0], "CF", 2) == 0) { // first two characters match "CF"
  // ...
}
{
  // take a single character out of the string
  char character = text[4];
  Serial.print(character); // prints 'L'
}
{
  // take a substring (but first consider whether you *really* have to copy it)
  char firstField[3]; // this can store a string of 2 characters (+ terminating null character)
  strncpy(firstField, &text[2], 2); // copy "02"
  firstField[2] = '\0'; // null-terminate the string
  Serial.print(firstField); // prints "02"
}
{
  // alternatively
  char firstField[3] = {'\0'}; // initialize firstField[0] with a null character
  strncat(firstField, &text[2], 2); // copy "02" and null-terminate
  Serial.print(firstField); // prints "02"
}
{
  // convert substring to int
  char tmp = text[9];
  text[9] = '\0'; // tell atoi where to stop
  int value = atoi(&text[5]); // value is now 125
  text[9] = tmp; // restore the original string
}
{
  // convert substring to double/float
  char tmp = text[25];
  text[25] = '\0'; // tell strtod where to stop
  double value = strtod(&text[19], nullptr); // value is now 8.556
  text[25] = tmp; // restore the original string
}

Pieter

Lindbaum:
What would you recommend?

something like this… moving a pointer along your string:

expects:

[FL010100]

code:

const size_t MAX_MESSAGE_BUFFER_LENGTH = 16;

template<class T> inline Print &operator << (Print &object, T argument)
{
  object.print(argument);
  return object;
}

void setup()
{
  Serial.begin(9600);
  if(Serial)
  {
    Serial << (F("let's go!\n"));
  }
}

void loop()
{
  if (char* packet = checkForNewMessage(Serial, '[', ']'))  // checks for message on Serial with start marker of "[" and end marker of "]"
  {
    Serial << (F("\nthis just in...\n")) << (packet) << (F("\n\n"));
    //FL010100
    char firstPart[3];
    char* ptr = packet;
    firstPart[0] = *ptr++;
    firstPart[1] = *ptr ++;
    firstPart[2] = '\0';
    char secondPart[3];
    secondPart[0] = *ptr++;
    secondPart[1] = *ptr++;
    secondPart[2] = '\0';
    char thirdPart[5] = "";
    strcat(thirdPart, ptr);
    Serial << (F("First Part = ")) << (firstPart) << F("\n");
    Serial << (F("Second Part = ")) << (secondPart) << F("\n");
    Serial << (F("Third Part = ")) << (thirdPart) << F("\n");
  }
}

char* checkForNewMessage(Stream& stream, const char startMarker, const char endMarker)
{
  static char incomingMessage[MAX_MESSAGE_BUFFER_LENGTH] = "";
  static unsigned char idx = 0;
  static bool gotStartMarker = false;
  if (stream.available())
  {
    if (!gotStartMarker)
    {
      if (stream.read() == startMarker)
      {
        gotStartMarker = true;
      }
    }
    else
    {
      incomingMessage[idx] = stream.read();
      if (incomingMessage[idx] == endMarker)
      {
        incomingMessage[idx] = '\0';
        idx = 0;
        gotStartMarker = false;
        if (!strlen(incomingMessage)) //startMarker followed immediatly by endMarker (i.e.no data)
        {
          //stream << (F("{\"error\":\"no data\"}\n"));  // you can return an error to sender here
          return nullptr;
        }
        //stream << (F("{\"success\":\"")) << (incomingMessage) << (F("\"}\n"));  // or return a success messaage
        return incomingMessage;
      }
      else
      {
        idx++;
        if (idx > MAX_MESSAGE_BUFFER_LENGTH - 1)
        {
          stream << (F("{\"error\":\"message exceeded ")) << (sizeof(incomingMessage) - 1) << (F(" chars\"}\n"));  // another error to sender here
          idx = 0;
          gotStartMarker = false;
          incomingMessage[idx] = '\0';
        }
      }
    }
  }
  return nullptr;
}
template<class T> inline Print &operator << (Print &object, T argument)

{
  object.print(argument);
  return object;
}

Quite clever! Why didn’t they include that in the Arduino core?

PieterP:
Quite clever! Why didn't they include that in the Arduino core?

too scary...

Thanx a lot - the pointer solution worked perfect :slight_smile: