help with String manipulation

JT007:
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().

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 ....

GoForSmoke:
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

Not without terminating zeros. Go ahead and try.

GoForSmoke:
Not without terminating zeros. Go ahead and try.

Sure

// 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

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

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

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.

PaulS:

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.

@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):

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:

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.

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

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") {
 
  }
String stringOne = "Content-Type: text/html";
 
  // substring(index) looks for the substring from the index position to the end:
   if (stringOne.substring(19) == "htm") {
    }

O
0

guess what the difference is

NULL is zero, not |

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