Go Down

Topic: indexOf does not work with a string value? (Read 1 time) previous topic - next topic

mistergreen

Code: [Select]

  String mystring = "GET /http://arduino/?page=1&time=20,40,30,2,14,2013&param2=54& HTTP/1.1";
  int a = mystring.indexOf('time');
  int b = mystring.indexOf('&',a+1);
  Serial.println ( "substring: "+ mystring.substring(a,b) );



the above yields 'e=1'
It seems to work fine is the value in indexOf is one character but blows up with a string.

any info would be good. thanks.

Nick Gammon

Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics


mistergreen

#3
Feb 15, 2013, 03:56 pm Last Edit: Feb 15, 2013, 03:59 pm by mistergreen Reason: 1
thanks, that did it. I had no idea a double quote made a difference.

And thank goodness the arduino has it's own String methods. Using C string methods were a pain.


Arrch


thanks, that did it. I had no idea a double quote made a difference.

And thank goodness the arduino has it's own String methods. Using C string methods were a pain.




Hopefully you don't plan on doing anything that push's the limits of the microcontrollers already limited SRAM.

PeterH


And thank goodness the arduino has it's own String methods. Using C string methods were a pain.


The c-string equivalents need hardly any more code, and avoid you needing to use the Arduino String class and the memory-related bugs that come with it. Unless you have patched your Arduino installation to correct these bugs, the String class is currently not safe to use. Even if you do fix the bugs, storing variable length dynamic data in the heap is asking for trouble on such a memory-limited architecture.
I only provide help via the forum - please do not contact me for private consultancy.

mistergreen

Oh, I didn't know the String object was such a problem.

How would I do the above code with C?

using strtr ?

My problem with the C string is converting the pointers returned into char so I can store them in a variable or array.

PeterH


using strtr ?


You can use strstr() to locate a string within another string, and substr() to extract part of a string into another variable. In your example, two calls to strstr() to locate the start and end of the section of interest, and one call to substr() to extract it into another buffer, would achieve the same effect as your original code. The two implementations would be pretty similar in terms of source code length and complexity.
I only provide help via the forum - please do not contact me for private consultancy.

Nick Gammon


And thank goodness the arduino has it's own String methods. Using C string methods were a pain.


Please note that, at present, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.).

Alternatively, install the fix described here:
  http://arduino.cc/forum/index.php/topic,145765
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

mistergreen



using strtr ?


You can use strstr() to locate a string within another string, and substr() to extract part of a string into another variable. In your example, two calls to strstr() to locate the start and end of the section of interest, and one call to substr() to extract it into another buffer, would achieve the same effect as your original code. The two implementations would be pretty similar in terms of source code length and complexity.


substr() is a C++ <string> method. ANy other options?

Nick Gammon

Maybe it's an overkill but you could use a regular expression to parse the string. Example:

Code: [Select]

#include <Regexp.h>

char * mystring = "GET /http://arduino/?page=1&time=20,40,30,2,14,2013&param2=54& HTTP/1.1";

void setup ()
{
  Serial.begin (115200);
  MatchState ms;
  ms.Target (mystring);  // what to search

  char result = ms.Match ("time=(%d+),(%d+),(%d+),(%d+),(%d+),(%d+)");
  if (result == REGEXP_MATCHED)
    {
    char buf [10];  // to hold results
    int num;
    for (int i = 0; i < 6; i++)
      {
      Serial.print ("Result ");
      Serial.print (i);
      Serial.print (" = ");
      if (ms.capture [i].len < sizeof buf)
        {
        num = atoi (ms.GetCapture (buf, i));
        Serial.println (num);
        }
      else
        Serial.println ("(too long)"); 
      }  // end for loop
    }  // end if matched
  else if (result == REGEXP_NOMATCH)
    {
    Serial.println ("Did not match.");
    }
  else
    {
    Serial.println ("Error in regular expression.");
    }
}  // end of setup

void loop () { }


Output:

Code: [Select]

Result 0 = 20
Result 1 = 40
Result 2 = 30
Result 3 = 2
Result 4 = 14
Result 5 = 2013


Library from: http://gammon.com.au/Arduino/Regexp.zip

Documentation: http://www.gammon.com.au/forum/?id=11063
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

spatula


substr() is a C++ <string> method. Any other options?

The c equivalent of a string is an array of char, so when you know the start and end position of the "substring" within the larger one you can just copy the array elements into a new array. Or if you need to make a comparison you may use the 'n' variant (strncmp) which compares two strings up to a certain number of characters.

I very much like the solution based on regular expressions. Mine, however, is the opposite. I see you are trying to parse the parameters of a query string. Your problem is quite specific and a less generic solution may work better in your case. Consider a loop on each character of the string.

Start by locating the '?' sign, i.e. the beginning of the query string, then:
1. save the current position (+1) into a variable (e.g., name_start). From that position, start looking for the first '=' sign. The array between name_start and the position of '=' is the parameter name.
2. save the current position (+1) into a variable (e.g., value_start). From that position, start looking for the first '&' sign or space.
The array between value_start and the position of '&' or space is the parameter value.
3. If you found a space exit the loop, otherwise repeat from 1.

You could then make improvements to make it more robust, e.g.: manage the premature end of the query string, manage spaces or url-encoded characters, but this should give you a start.

PeterH


substr() is a C++ <string> method. ANy other options?


You could use strncpy().
I only provide help via the forum - please do not contact me for private consultancy.

mistergreen

#13
Feb 16, 2013, 04:07 am Last Edit: Feb 16, 2013, 04:17 am by mistergreen Reason: 1
For those interested, I got it to work with this SORT OF.. I used Xcode to write this (it's not fun to test on the arduino).
I wish arduino uses objective C :)

Code: [Select]

   char mystring[] = "GET /http://arduino/?page=1&time=20,40,30,2,14,2013&param2=54 HTTP/1.1";
   char temp1[40];
   char temp2[40];
   
   char *a = strstr(mystring, "time");
   strncpy(temp1, a, sizeof(temp1));
   
   char *b = strstr(temp1, "&");
   
   strncpy(temp2, a, b-temp1);
   
   printf("%s  :  %s ", temp1, temp2 );


output
Code: [Select]
time=20,40,30,2,14,2013&param2=54 HTTP/1
 :  time=20,40,30,2,14,2013



but if I change the keyword search to 'page', I get some pointer junk at the end of the string.
output
Code: [Select]
page=1&time=20,40,30,2,14,2013&param2=54
 :  page=1\231\333h


Any ideas? Somehow convert the 'b' pointer to an integer?

Nick Gammon

Code: [Select]
page=1&time=20,40,30,2,14,2013&param2=54 HTTP/1.1

is 49 characters long.

Warning:

Quote

No null-character is implicitly appended at the end of destination if source is longer than num (thus, in this case, destination may not be a null terminated C string).
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Go Up