Extracting characters from a String

Hello, I use Arduino Mega 2560. On UART port 3 I read data and I store them in

String incomingString; // for incoming serial data

These data are in the format:

A: 123 B: 5674 C:891

I want to gather only the data in A:

A: 123

and neglect the other data, and send the data from A to Serial 0. After searching on google: I found this:

#include <string>
#include <cstring>

bool Extract(const std::string& name, std::string& ret)
{
    const char *begin = strchr(name.c_str(), '#');
    if (begin == 0)
        return false;
    const char *end = strchr(begin, '/');
    if (end == 0)
        return 0;
    ret = std::string(begin + 1, end - begin);
    return true;
}

from this website:

http://www.cplusplus.com/forum/general/10429/

I changed it to:

#include <string>
#include <cstring>

bool Extract(const std::string& name, std::string& ret)
{
    const char *begin = strchr(name.c_str(), 'A');
    if (begin == 0)
        return false;
    const char *end = strchr(begin, 'B');
    if (end == 0)
        return 0;
    ret = std::string(begin + 1, end - begin);
    return true;
}

and I call it like this:

Extract(incomingString, returnString);

But it shows me a lot of errors… Is there any other way?

First make your mind up whether you want to use Strings (uppercase S) which are objects created using the Arduino String library

or

C style strings (lowercase s) which are zero terminated arrays of chars

Using the former in the Arduino environment is usually regarded as a bad idea in the small memory environment of the average Arduino because of the memory fragmentation they cause. I note, however, that Strings are used extensively in programs for the ESP8266 and ESP32 but they do have more memory than the AVR based boards

From the little information that you have posted it seems that your are trying to parse a String using functions designed to work with strings

Please post a complete sketch and the associated error messages

#include <string.h>
#include <cstring.h>

String incomingString; // for incoming serial data
String returnString; // the return 


bool Extract(const std::string& name, std::string& ret)
{
    const char *begin = strchr(name.c_str(), 'A');
    if (begin == 0)
        return false;
    const char *end = strchr(begin, 'B');
    if (end == 0)
        return 0;
    ret = std::string(begin + 1, end - begin);
    return true;
}


void setup() 
{
   // put your setup code here, to run once:
   Serial3.begin(9600);
   Serial.begin(38400);
}

void loop() 
{
   // send data only when you receive data:
   if (Serial3.available() > 0) 
   {
       // read the incoming byte:
       incomingString = Serial3.readString();

     Extract(incomingString, returnString);
    }
    Serial.println(returnString);
}

if you're going to use c string functions, why not pass a c-string to the sub-function

consider

result

extract
extract: a 123, b 5674 c 891
extract: false for A: 12 B 34 D 55
extract: a 3, b 999 c 400
const char inp [] = "A: 123 B: 5674 C:891";
String     inp2    = "A: 3   B: 999  C:400";

char s [100];

// -----------------------------------------------------------------------------
bool extract (
    const char *inp )
{
    int a, b, c;
    if (3 > sscanf (inp, "A: %d B: %d C: %d", &a, &b, &c))  {
        sprintf (s, "%s: false for %s", __func__, inp);
        Serial.println (s);

        return false;
    }

    sprintf (s, "%s: a %d, b %d c %d", __func__, a, b, c);
    Serial.println (s);

    return true;
}

// -----------------------------------------------------------------------------
void setup (void)
{
    Serial.begin (9600);
    Serial.println ("extract");

    extract (inp);
    extract ("A: 12 B 34 D 55");
    extract (inp2.c_str());
}

void loop (void) {}

a more geneic approach could capture the label (e.g. "A") in a string array and the value in a 2nd array and return the number of values captured

I am trying this modification:

incomingString = Serial3.readStringUntil('B');

but it prints the whole data line except for letter 'B'. How can this be?

edit: @gcjr: Ok, I will check it..

alex5678:
I am trying this modification:

incomingString = Serial3.readStringUntil('B');

but it prints the whole data line except for letter 'B'. How can this be?

edit: @gcjr: Ok, I will check it..

Do you mean that it prints the letters before and after the B ?

Post your amended code. It sounds like the check for a B is in a while loop that continues after the B is reached

char yourString[] = "A: 123 B: 5674 C:891"
val = strtol(&yourString[2], NULL, 10);

After this, val == 123.

@UKHeliBob: Sorry for the delay:

Do you mean that it prints the letters before and after the B ?

Yes!

void loop(void) 
{
    Serial3.flush();
    Serial.flush();
    incomingString = " ";
    if (Serial3.available() > 0) 
    {
        incomingString = Serial3.readStringUntil('B');
    }
    Serial.flush();
    Serial.print(incomingString); 
    incomingString = " ";;
    delay(500);
}
    Serial.flush();

This looks an attempt to remove unwanted incoming characters from the Rx buffer after the B has been found. However, what Serial.flush() does is to wait until all characters in the Tx buffer have been sent. If you want to remove characters from the Rx buffer then you need to read and discard them until no more are available

UKHeliBob:

    Serial.flush();

This looks an attempt to remove unwanted incoming characters from the Rx buffer after the B has been found. However, what Serial.flush() does is to wait until all characters in the Tx buffer have been sent. If you want to remove characters from the Rx buffer then you need to read and discard them until no more are available

How do I achieve that?

while (Serial.available())
{
  Serial.read();  //read and discard
}