Pages: 1 [2]   Go Down
Author Topic: help with String manipulation  (Read 1550 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Tesla Member
***
Karma: 148
Posts: 9753
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I was hoping that there would be a straight forward solution like SlaveID=mid(cstring,0,3) - good old VB

There is the below.

http://arduino.cc/en/Reference/StringObject
http://www.arduino.cc/en/Tutorial/TextString

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Lake District, UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 72
Electronics needs smoke to work, if it escapes its broken
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Zoomkat,
i saw the information you pointed out,
unfortunately i couldnt find an example which would simply strip characters from a string between linits.
could you provide me with a direct link to the example
cheers
Jason
Logged

0
Offline Offline
Tesla Member
***
Karma: 148
Posts: 9753
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Zoomkat,
i saw the information you pointed out,
unfortunately i couldnt find an example which would simply strip characters from a string between linits.
could you provide me with a direct link to the example
cheers
Jason

The below shows how to find the position of a delimiting character in a string, then using an offset, find the location of the next delimiting character in the string. Once you know the positions of the two characters, you can use those locations to capture the substring between the two like in the bottom example.

http://arduino.cc/en/Tutorial/StringIndexOf

http://arduino.cc/en/Tutorial/StringSubstring
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Lake District, UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 72
Electronics needs smoke to work, if it escapes its broken
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes i understand what you are saying but unfortunately i dont have delimiting characters
 the format is 255O255|the part of the code which is handling the parsing does not see the end character "|" which has already been stripped.
i need to be able to use the character position instead.
the examples dont offer any suggestion on how to do this.

as mentioned above i could in VB.

I am currently going back over the code and seeing if i can adopt Pauls suggestion.

thanks for the help
J.
Logged

Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 361
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

with
cmd="255O255|";

preconditions
strlen(cmd)==8
&& cmd[3]=='O'
&& cmd[7]=='|' )

int slave=atoi( cmd);     // gives you the address
int value=atoi( cmd+4); // gives you the value

Doesn't that "get you there from here"?

Also are you sure about the 3 digit thing?
i.e. you will be getting "023O004|" not "23O4|"

John
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4837
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes i understand what you are saying but unfortunately i dont have delimiting characters
 the format is 255O255|the part of the code which is handling the parsing does not see the end character "|" which has already been stripped.
i need to be able to use the character position instead.
the examples dont offer any suggestion on how to do this.

Using a 4 char array string you can put the first 3 serial chars in array[0], [1], [2], and make [3] = 0.
Then you have a C string suitable for atoi().

Quote
i need to be able to use the character position instead.
the examples dont offer any suggestion on how to do this.

Make a variable to hold the final number.
**1** Multiple final number variable by 10.
**2** Read the 1st serial char, check that it is >= '0' and <= '9' and if so,
  subtract '0' and add to the final number variable.
Repeat **1** and **2** two more times.
If no errors then you have read 3 digits and your converted value is in the final number variable.

Otherwise rely on black box function until you learn how simple the basis for the above is.

C++ container classes on an UNO is like Formula 1 cars on a half acre dirt track.
Possible but ....

Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 361
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Using a 4 char array string you can put the first 3 serial chars in array[0], [1], [2], and make [3] = 0.
Then you have a C string suitable for atoi().

array and array+4 are already suitable for atoi:

int xxx = atoi(array);
int yyy = atoi(array+4);

John
« Last Edit: January 27, 2013, 02:40:08 pm by johncc » Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4837
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not without terminating zeros. Go ahead and try.
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 361
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not without terminating zeros. Go ahead and try.

Sure

Code:
// Return true if a valid cmd "xxxOyyy|" , false if not
// output parameters xx and yy
bool parse_O_command( const char * str, int & xx, int & yy)
{
// "Input string should arrive in the format of 255O255|"
if ( strnlen(str,8)== 8 && str[3]=='O' && str[7]=='|'){
xx=atoi(str);    // the first 3 characters are the Slave device address
yy=atoi(str+4);    // str[4] and after are digital value
return true;
}
return false;
}

Test Suite
Code:

void setup(){

int adr, val;
bool valid;

valid = parseOcommand("123O456|", adr, val);
Serial << "1: " << adr << "," << val << " : " << (valid?"valid":"not a valid") << " O command" << endl;

char buf8[8] = {'2','4','6','O','1','8','8','|'};
valid = parseOcommand(buf8, adr, val);
Serial << "2: " << adr << "," << val << " : " << (valid?"valid":"not a valid") << " O command" << endl;

char buf7[7] = {'2','4','6','O','1','7','7'};
valid = parseOcommand(buf7, adr, val);
Serial << "3: " << adr << "," << val << " : " << (valid?"valid":"not a valid") << " O command" << endl;

Serial << "Done" << endl;
}

Output

Code:
1: 123,456 : valid O command
2: 246,188 : valid O command
3: 246,188 : NOT valid O command
Done

Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 654
Posts: 50936
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Not without terminating zeros. Go ahead and try.
The initial string is, presumably, NULL terminated. The atoi() function stops processing when it encounters a NULL or when it encounters some non-integer character. So, NULL terminating is not technically required, since it is the original array that is being passed to atoi(), twice.

If the parts of the original array were copied to other arrays, then, the copies would need to be NULL terminated.
Logged

Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 361
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Not without terminating zeros. Go ahead and try.
The initial string is, presumably, NULL terminated. The atoi() function stops processing when it encounters a NULL or when it encounters some non-integer character. So, NULL terminating is not technically required, since it is the original array that is being passed to atoi(), twice.

If the parts of the original array were copied to other arrays, then, the copies would need to be NULL terminated.

Thank you.  And even that last warning would not be important if the format is "xxxOyyy|", as per original post.   But I think he said later that maybe there is no | terminator.
Logged

Global Moderator
Melbourne, Australia
Offline Offline
Brattain Member
*****
Karma: 511
Posts: 19367
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@OP are you writing both ends?

In that case just send a struct, rather than mucking around with delimiters, atoi, substrings, etc. I wrote a simple library on this page (for RS485 too):

http://www.gammon.com.au/forum/?id=11428

That lets you send a block of memory (ie. a struct) complete with start and end terminators (so you don't come in halfway through a piece of data), and a sumcheck. An example struct could be:

Code:
typedef struct
  {
  byte command; 
  long arg;
  } tCommand;


That lets you send a command to your device with a long (32-bit) argument being some sort of argument to that command.
Logged

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

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

0
Offline Offline
Tesla Member
***
Karma: 148
Posts: 9753
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Yes i understand what you are saying but unfortunately i dont have delimiting characters
 the format is 255O255|the part of the code which is handling the parsing does not see the end character "|" which has already been stripped. i need to be able to use the character position instead. the examples dont offer any suggestion on how to do this.

Not sure what the problem is, but the bottom code shows  how to get the desired characters from a string. Will your string always have an O between the two desired numbers? If so you should be able to atoi the initial string to get the first 255 number, and get the rest of the string past the center O and atoi it also. I do this to parse GET strings.

255O255

Code:
String stringOne = "Content-Type: text/html";
 
  // you can also look for a substring in the middle of a string:
   if (stringOne.substring(14,18) == "text") {
 
  }

Code:
String stringOne = "Content-Type: text/html";
 
  // substring(index) looks for the substring from the index position to the end:
   if (stringOne.substring(19) == "htm") {
    }
 
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4837
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

O
0

guess what the difference is

NULL is zero, not |

Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Lake District, UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 72
Electronics needs smoke to work, if it escapes its broken
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the replies,
i have taken onboard all of your ideas and given them all a try.

As Nick has noticed, i still working on a RS485/modbus communication project

the command was going to be the device ID xxx - a function "o" being Output (Digital) and yyy being the value/byte sent to the slave device to drive the digital values which are Bit weighted.

This was going to be the structure and would be similar format for all commands from a host PC to the RS485 master device.
the numbering format was to be 3 characters no matter what and the function would always be a character.

From Pauls earlier post the comma delimited suggestion appears to be the most simplistic and straight forward method.

It should now allow me to to create address IDs of any size - say 4000      The function command could be similar, i will probablly keep to values in 1 byte ie, 0 to 255 as Nick Gammons RS485 comms example uses Bytes in the message transfer.

Its a steep learning curve, thank you all for your assistance, much appreciated
Logged

Pages: 1 [2]   Go Up
Jump to: