Code Review: Parsing a String

Hi All,

In working with the cloud API passing and parsing arguments in string form is pretty critical. I’m a newbie, and want to parse the argument/parameter at the end of the http post efficiently into either a series of integers or an integer array.

The integers will then be scaled against a total value of 30 - so some int -> float -> int messiness was necessary.

I have this code working as a prototype (doesn’t need spark.function input) but it seems really long winded. If anyone has time to take a look and make suggestions for improving it - I would be very grateful.

Also, I need a method for rounding one of the three numbers up if the sum of the 3 ints is <30. I wasn’t sure how to approach this.

Much thanks,
Rob

String args = "15,11,22,43";
   //Index the string for commas
int commaIndex = args.indexOf(',');
int secondCommaIndex = args.indexOf(',', commaIndex+1);
int thirdCommaIndex = args.indexOf(',', secondCommaIndex+1);



void setup() {
  Serial.begin(9600);
}


void loop() {
 

 //parse input string
   String lastCompleteCount = args.substring(0, commaIndex);
   String JiraStartCount = args.substring(commaIndex+1, secondCommaIndex);
   String JiraProgCount = args.substring(secondCommaIndex+1, thirdCommaIndex); // To the end of the string
   String JiraClosedCount = args.substring(thirdCommaIndex+1);
  
  //convert to integers
   int bellCount = lastCompleteCount.toInt();
   int StartCount = JiraStartCount.toInt();
   int ProgCount = JiraProgCount.toInt();
   int ClosedCount = JiraClosedCount.toInt();
  
  //find the ratio of the total issue count / 30
  float IssueRatio = float(StartCount + ProgCount + ClosedCount)/30;
  
  
  //Print results for debug
  Serial.println(IssueRatio);
  Serial.println(bellCount);
  //Print Scaled issue counts for debug
  Serial.println(int(StartCount/IssueRatio));
  Serial.println(int(ProgCount/IssueRatio));
  Serial.println(int(ClosedCount/IssueRatio));
  Serial.println("-----");
}

I quite like the oldfashioned C way to handle strings :wink:

You could have a go with strtok() for splitting up your args.c_str() in a loop.
This way you can treat each individual token just like all the others rather than treating each and everyone separately.


For reference you can search this forum for c_str and or search or google for strtok.
atoi is another one worth googling.

3 Likes

In particular, every one of the substring method calls on a String object uses RAM. Using a lot of small RAM space like that can lead to heap fragmentation over time and make your program less reliable.

a type of approach (using already endorsed C strings):

void setup() 
{
  Serial.begin(9600);
  String args = "15,11,22,43";
  int value[4];
  const char* stringArgs = args.c_str();
  Serial.println(stringArgs);
  char* myCopy = strtok(strdup(stringArgs), ",");
  for (int i = 0; i < 4; i++)
  {
    value[i]= atoi(myCopy);
    Serial.println(value[i]);
    myCopy = strtok(NULL, ","); 
  }  
}
void loop() 
{
  
}

Do you simply want to add to the lowest number to get up to 30?

void setup() 
{
  Serial.begin(9600);
  String args = "15,11,22,4";
  int value[4];
  const char* stringArgs = args.c_str();
  Serial.println(stringArgs);
  char* myCopy = strtok(strdup(stringArgs), ",");
  for (int i = 0; i < 4; i++)
  {
    value[i]= atoi(myCopy);
    Serial.println(value[i]);
    myCopy = strtok(NULL, ","); 
  }  
  // let's sum the three values:
  int sum = 0;
  int lowest = 1;
  for (int i = 1; i < 4; i++)
  {
    sum += value[i];
    if (value[i] < value[lowest]) lowest = i;
  }
  char buffer[41];
  sprintf(buffer, "The lowest value is %d, the sum is %d", value[lowest], sum);
  Serial.println(buffer);
  if (sum < 30)
  {
    value[lowest] += (30-sum);
    buffer[0] = '\0';
    sprintf(buffer, "So I have adjusted value %d by %d.", lowest, 30-sum);
    Serial.println(buffer);
  }
  //  
}
void loop() 
{
  
}
3 Likes

@BulldogLowell, just a word of caution.
Since strdup() does malloc() some space for the duplicated string, you’ll normally need to free() that allocated memory again.


@cablecutter, by use of strtok() you can extend @BulldogLowell 's code to accept as many tokens as you want if you change the for() for a while() like this

  while (myCopy != NULL)  
  {
    ...
    myCopy = strtok(NULL, ","); 
  }

Then you only need to be careful to have a value[] big enough to hold all your integer values.

4 Likes

good eye :wink:

1 Like