Best way to parse values from a string?

Aug 31, 2017 at 11:14pm
Hi

I'm writing some code for the Arduino and wanted to parse some settings that will be inputted. The settings must be DIGITS1 = DIGITS2, DIGITS3 = DIGITS4 etc - like the following

 
  2 = 202,1 = 103, 9 = 202

Spaces don't matter and there can be multiple identities (separated by a comma) or only one. At the moment, I'm just looking to see whether its valid

Is there an easy way to do this on the Arduino? Would regex help here (assuming there is a library for it on Arduino?

I've written the below which seems to work following some tests but its long and ugly!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
bool checkSettings (String settingStr)
{
  if (settingStr.length() == 0)    //settings cannot be empty
      return false;
  
  for (int i = 0; i < settingStr.length(); i++) //this deals with the whole string
  {
      bool firstNum = false, secondNum = false, equalsSign = false; //these mark whether each sentence has required characters

      for (int j = i; j < settingStr.length(); j++) //this deals with each sentence
      {
        if (firstNum && secondNum && equalsSign) //for this sentence we have found all required elements
        {

          if (settingStr[j] != ',' && j != settingStr.length() - 1)  //should end with a comma or be the end of the whole string otherwise fail
            return false;
            
          else    //finished with this sentence move to next
          {
            i = j;
            break;
          }
        }

        if (!firstNum)   //expecting first number
        {
          if (settingStr[j] == ' ')
            continue;
          
           if (!isDigit(settingStr[j]))  //return false as must be a digit
              return false;

           for (int k = j + 1; j < settingStr.length(); k++) //see what trails the first digit
           {
              if (!isDigit(settingStr[k]))  //not a digit so stop looking
              {
                  firstNum = true;   //found our number
                  j = k;  //set j back to our non-digit index
                  break;
              }
           }
        }

        if (firstNum  && !equalsSign )  //expecting equals sign
        {
           if (settingStr[j] == ' ')
              continue;
            
            if (settingStr[j] != '=') 
              return false;

            else
            {
              j = j + 1;
              equalsSign = true;
            }
        }

        if (firstNum && equalsSign && !secondNum) //expecting third number
        {       
              if (settingStr[j] == ' ')
                continue;

              if (!isDigit(settingStr[j]))  //return false as must be a digit
                  return false;

              for (int l = j + 1; l < settingStr.length(); l++)
              {
                  if (!isDigit(settingStr[l]) || l == settingStr.length() - 1)  //if next character not a digit or end of whole sentence then go to exit procedure above
                  {
                    secondNum = true;
                    j = l - 1;
                    break;
                  }
              }
        }
      }
  }
  return true;
}


Thanks
Last edited on Aug 31, 2017 at 11:15pm
Sep 1, 2017 at 7:44am
I am not sure what is available on the Arduino.
Normally you can use a stringstream and getline to split your string into substrings with ',' as separator.

For each string you can use the find method of the string to locate the '=' and use the substring function get the key and value. Finally you convert the value to an int.
OR
You could use a second stringstream and use >> to extract the key, '=', and value.
Sep 1, 2017 at 8:53am
Found some spare minutes and hacked together this demo. Maybe easier to understand than my explanation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <cstdlib>

using namespace std;

vector<string> SplitString(const string& s, char sep = ',')
{
  vector<string> v;
  stringstream ss(s);
  string token;
  while (getline(ss, token, sep))
  {
    v.push_back(token);
  }
  return v;
}

bool SplitString(const string& input, int& key, int& val, char sep = '=')
{
  stringstream ss(input);
  char separator;
  int tempKey, tempValue;
  if (!(ss >> tempKey >> separator >> tempValue))
    return false;
  if (separator != sep)
    return false;

  key = tempKey;
  val = tempValue;

  return true;
}

int main()
{
  const string input = "2 = 202,1 = 103, 9 = 202";
  vector<string> tokens = SplitString(input);
  int key, val;
  for (const string& s : tokens)
  {
    if (SplitString(s, key, val))
    {
      cout << "Key = " << key << "\t" << "Value= " << val << "\n";
    }
  }
}

OUTPUT

Key = 2 Value= 202
Key = 1 Value= 103
Key = 9 Value= 202
Sep 1, 2017 at 1:27pm
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <string>
#include <sstream>

int main()
{
    // SIMULATE INPUT STREAM
    std::istringstream iss;
    std::string input = "2 = 202,1 = 103, 9 = 292, 4 = 402,3 = 773, 8 = 678";
    iss.str (input);
    
    int n1 = 0, n2 = 0;
    char ch1, ch2;
    
    // PROCESS STREAM
    while(iss >> n1 >> ch1 >> n2)
    {
        std::cout << n1 << ' ' << n2 << '\n';
        if(iss.tellg() == -1)
            break;
        else
            iss >> ch2;
    }
    
    return 0;
}


std::string input = "2 = 202,1 = 103, 9 = 292, 4 = 402,3 = 773, 8 = 678";

2 202
1 103
9 292
4 402
3 773
8 678
Program ended with exit code: 0




std::string input = "2 = 202";

2 202
Program ended with exit code: 0
Sep 1, 2017 at 4:33pm
Topic archived. No new replies allowed.