Analysing Strings?

Hi everyone,

I have a String (not 's') which I would like to analyse character by character to emulate a state machine-like system. Basically, I'm looking for a specific phrase and I wanted to store the value which appears right next to the phrase. How can I go about doing this? I've got the basic concept but still am unsure of how to implement in the IDE.

Thanks :slight_smile:

As an exercise, or a real application?

Both really (an exercise for later application)!

I have a String (not 's')

You are obviously aware of the difference between the two. Is there a particular reason why you are using a String rather than a string ?

Are they interchangeable? I am only using String because it was a part of an example sketch.

You should not use Strings (capital S) in the small memory of an Arduino - they can cause corruption. Use strings (small s).

Have a look at Serial Input Basics - it includes a parse example.

You may also find the strcmp() function useful.

...R

For strings (lower case s), also look at strstr to find a substring and strchr to find a character.

Dear fhqwhgads,

Yes, you shouldn't use String for many reasons, most of which are advanced topics. They will cause subtle, inexplicable failures, so it's best to not start down that path.

Here is a C string implementation that watches for "KEYWORD=", using a Finite-State machine:

enum state_t { RX_KEYWORD, RX_SEPARATOR, RX_VALUE };  // The possible states
static state_t state; // A variable of that enumerated type (basically an integer)

static char    keyword[] = "KEYWORD";  // The string to watch for
static uint8_t keywordIndex;           // How much has matched so far

static int16_t value = 0;               // Value to save
//static char    value[ 32 ];             // Value to save
//static float   value = 0;               // Value to save

static bool emptyValue = true;

//===========================
// This FSM parses watches for a specific keyword.  As each character
//   is received, it either changes the current "state", or contributes
//   to a parameter's value.
//
// No temporary buffers are used, and invalid keywords are immediately
//   rejected.

bool getCommand( char c )
{
  bool gotIt = false; // Assume we're not done.

  switch (state) {

    case RX_KEYWORD:          //--------------------------------
      if (c == keyword[ keywordIndex ]) {
        // Another char matched, step to the next one.
        keywordIndex++;

        if (keywordIndex == sizeof(keyword)-1) {
          // All matched, start watching for the separator
          state = RX_SEPARATOR;
        }
     } else {
        // Didn't match, restart
        keywordIndex = 0;
      }
      break;

    case RX_SEPARATOR:       //--------------------------------
      if (c == '=') {
        emptyValue = true;
        value      = 0;
        state      = RX_VALUE;
      } else {
        // Restart
        keywordIndex = 0;
      }
      break;

    case RX_VALUE:           //--------------------------------
      if (isdigit( c )) {
        emptyValue = false;
        value      = value*10 + (c - '0'); // accumulate another digit
      } else {
        gotIt = true; // no more digits, indicate value is complete

        // Restart
        keywordIndex = 0;
        state = RX_KEYWORD;
      }
      break;

  }

  return gotIt;
}

//===========================

void setup()
{
  Serial.begin( 9600 );
  Serial.print( F("fghfgh example started.\n"
                  "Watching for \"") );
  Serial.print( keyword );
  Serial.println( F("=value\" strings.") );
}

//===========================

void loop()
{
  while (Serial.available()) {
    bool gotSome = getCommand( Serial.read() );

//    Serial.print( (uint8_t) state );  // Show the state for each char received
//    Serial.print( '/' );
//    Serial.print( keywordIndex );
//    Serial.print( ',' );

    if (gotSome) {
      Serial.print( F("Keyword received! value = ") );
      if (emptyValue)
        Serial.print( F("<empty>") );
      else
        Serial.print( value );
      Serial.println();
    }
  }
}

It's just a starting point. It does not recognize a string that contain portions of the keyword. For example, "KEYKEYWORD" would not be recognized as containing "KEYWORD", but you probably don't want to accept that, as it could be a valid, distinct string. I suspect the keywords are separated by delimiters (e.g., a comma or space) that cannot be part of the keyword.

There are placeholders for other value types, like char or float. If you want those types, give it a try and ask follow-up questions.

Cheers,
/dev

The TextFinder library is worth looking at, too.

Cheers,
/dev

I have a String (not 's') which I would like to analyse character by character to emulate a state machine-like system. Basically, I'm looking for a specific phrase and I wanted to store the value which appears right next to the phrase. How can I go about doing this? I've got the basic concept but still am unsure of how to implement in the IDE.

What code are you currently using? Below is a simple String method of finding a specific character string in a captured String, then obtaining the adjacent characters.

//zoomkat 3-5-12 simple delimited ',' string  
//from serial port input (via serial monitor)
//and print result out serial port

String readString, substring;
//String servo1;
int loc; 

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like AA BB01/10/2014 CC12:23:25 DD32.2 EE5432 FF54.35,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    //if (c == '\n') {  //looks for end of data packet marker

    if (c == ',') {
      Serial.println(readString); //prints string to serial port out
      //do stuff      
      loc = readString.indexOf("BB");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+12);
      Serial.print("date is: ");
      Serial.println(substring);

      loc = readString.indexOf("CC");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+11);
      Serial.print("time is: ");
      Serial.println(substring);

      loc = readString.indexOf("DD");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+6);
      Serial.print("DD is: ");
      Serial.println(substring);

      loc = readString.indexOf("EE");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+6);
      Serial.print("date is: ");
      Serial.println(substring);

      loc = readString.indexOf("FF");
      //Serial.println(loc);
      substring = readString.substring(loc+2);
      Serial.print("FF is: ");
      Serial.println(substring);      

      readString=""; //clears variable for new input
      substring=""; 

    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

@f..., Is this a follow-up to your previous question?

Did you read the links from all the posts there?

What did you try?

What isn't working?

It seems like you're asking the same question again, but we don't know why our previous answers didn't work for you. These answers are very similar, including why you shouldn't use the String class.

Cheers,
/dev

The code I am using is the example one provided:

/*
  String to Integer conversion

 Reads a serial input string until it sees a newline, then converts
 the string to a number if the characters are digits.

 The circuit:
 No external components needed.

 created 29 Nov 2010
 by Tom Igoe

 This example code is in the public domain.
 */

String inString = "";    // string to hold input

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // send an intro:
  Serial.println("\n\nString toInt():");
  Serial.println();
}

void loop() {
  // Read serial input:
  while (Serial.available() > 0) {
    int inChar = Serial.read();
    if (isDigit(inChar)) {
      // convert the incoming byte to a char
      // and add it to the string:
      inString += (char)inChar;
    }
    // if you get a newline, print the string,
    // then the string's value:
    if (inChar == '\n') {
      Serial.print("Value:");
      Serial.println(inString.toInt());
      Serial.print("String: ");
      Serial.println(inString);
      // clear the string for new input:
      inString = "";
    }
  }
}

The part that didn't work for me was replacing the String with the lower-case version for this type of implementation.

fghfghdfghtrdhdtrf:
I have a String (not 's') which I would like to analyse character by character to emulate a state machine-like system. Basically, I'm looking for a specific phrase and I wanted to store the value which appears right next to the phrase. How can I go about doing this? I've got the basic concept but still am unsure of how to implement in the IDE.

In case you want to find an "exact match" in a string (char array), the strstr() function is for you.

In case you want to seperate parts of a string into several substrings by finding "seperating characters" within the original string, maybe the strtok function can do for you.

It all depends on what you want to do.

If you cannot describe the details, perhaps provide an example of what you want!

The part that didn't work for me was replacing the String with the lower-case version for this type of implementation.

Please post the code you tried.