Arduino (C language) parsing string with delimiter (input through serial interface)
Didn't find the answer here :/
I want to send to my arduino through a serial interface (Serial.read()) a simple string of three numbers delimited with comma. Those three numbers could be of range 0-255.
Eg.
255,255,255
0,0,0
1,20,100
90,200,3
What I need to do is to parse this string sent to arduino to three integers (let's say r, g and b).
So when I send
100,50,30
arduino will translate it to
int r = 100
int g = 50
int b = 30
I tried lots of codes, but none of them worked. The main problem is to translate string (bunch of chars) to integer. I figured out that there will probably be strtok_r for delimiter purpose, but that's about it.
Thanks for any suggestions :)
To answer the question you actually asked, String objects are very powerful and they can do exactly what you ask. If you limit your parsing rules directly from the input, your code becomes less flexible, less reusable, and slightly convoluted.
Strings have a method called indexOf() which allows you to search for the index in the String's character array of a particular character. If the character is not found, the method should return -1. A second parameter can be added to the function call to indicate a starting point for the search. In your case, since your delimiters are commas, you would call:
int commaIndex = myString.indexOf(',');
// Search for the next comma just after the first
int secondCommaIndex = myString.indexOf(',', commaIndex + 1);
Then you could use that index to create a substring using the String class's substring() method. This returns a new String beginning at a particular starting index, and ending just before a second index (Or the end of a file if none is given). So you would type something akin to:
String firstValue = myString.substring(0, commaIndex);
String secondValue = myString.substring(commaIndex + 1, secondCommaIndex);
String thirdValue = myString.substring(secondCommaIndex + 1); // To the end of the string
Finally, the integer values can be retrieved using the String class's undocumented method, toInt():
int r = firstValue.toInt();
int g = secondValue.toInt();
int b = thirdValue.toInt();
More information on the String object and its various methods can be found int the Arduino documentation.
Use sscanf;
const char *str = "1,20,100"; // assume this string is result read from serial
int r, g, b;
if (sscanf(str, "%d,%d,%d", &r, &g, &b) == 3) {
// do something with r, g, b
}
Use my code here if you want to parse a stream of string ex: 255,255,255 0,0,0 1,20,100 90,200,3Parsing function for comma-delimited string
Simplest, I think, is using parseInt() to do this task:
void loop(){
if (Serial.available() > 0){
int r = Serial.parseInt();
int g = Serial.parseInt();
int b = Serial.parseInt();
}
}
does the trick.
I think you want to do something like this to read in the data:
String serialDataIn;
String data[3];
int counter;
int inbyte;
void setup(){
Serial.begin(9600);
counter = 0;
serialDataIn = String("");
}
void loop()
{
if(serial.available){
inbyte = Serial.read();
if(inbyte >= '0' & inbyte <= '9')
serialDataIn += inbyte;
if (inbyte == ','){ // Handle delimiter
data[counter] = String(serialDataIn);
serialDataIn = String("");
counter = counter + 1;
}
if(inbyte == '\r'){ // end of line
handle end of line a do something with data
}
}
}
Then use atoi() to convert the data to integers and use them.
This is great!
The last comment about "thirdvalue = 0" is true from the code given in the most upvoted response by #dsnettleton. However, instead of using "lastIndexOf(',');" , the code should just add a "+1" to "secondCommaIndex" like #dsnettleton correctly did for commaIndex+1 (missing +1 is probably just a typo from the guy).
Here is the updated piece of code
int commaIndex = myString.indexOf(',');
int secondCommaIndex = myString.indexOf(',', commaIndex+1);
String firstValue = myString.substring(0, commaIndex);
String secondValue = myString.substring(commaIndex+1, secondCommaIndex);
String thirdValue = myString.substring(secondCommaIndex+1); //To the end of the string
Example)
For a myString = "1,2,3"
commaIndex = 1 (Searches from index 0, the spot taken by the character 1, to the location of the first comma)
secondCommaIndex = 3 (Searches from index 2, the spot taken by the character 2, to the location of the next comma)
firstValue reads from index 0-1 = "1"
secondValue reads from index 2-3 = "2"
thirdvalue reads from index 4-4(the last index spot of the string) = "3"
Note: Don't confuse INDEX with the LENGTH of the string. The length of the string is 5. Since the String indexOf counts starting from 0, the last index is 4.
The reason why just
String thirdValue = myString.substring(secondCommaIndex);
returns 0 when using .toInt() is because thirdValue = ",3" and not "3" which screws up toInt().
ps. sorry to write all the instructions out but as a mech eng, even I sometimes would like someone to dumb down code for me especially having been in consulting for the past 7 years. Keep up the awesome posting! Helps people like me out a lot!
For n number delimited in string
int end;
while((end=str.indexOf(","))!=-1){
String num = str.substring(0,end);
str= asc.substring(end+1,str.length());
Serial.println(num);
}
The new SafeString Arduino library (available via the library manager) provides an stoken() method and a toLong() method which handles this case and avoids the heap fragmenation problems of the String class.
see https://www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html
for a detailed tutorial
#include "SafeString.h"
void setup() {
Serial.begin(9600);
createSafeString(appCmd, 50); // large enough for the largest cmd
createSafeString(token1, 10);
createSafeString(token2, 10);
createSafeString(token3, 10);
long r;
long g;
long b;
appCmd = "1,20a,100";
token1.clear();token2.clear();token3.clear(); // clear any old data
size_t nextIdx = 0;
nextIdx = appCmd.stoken(token1, nextIdx, ",");
nextIdx++; //step over delimiter
nextIdx = appCmd.stoken(token2, nextIdx, ",");
nextIdx++; //step over delimiter
nextIdx = appCmd.stoken(token3, nextIdx, ",");
nextIdx++; //step over delimiter
// now parse the numbers
bool have3ValidNumbers = true;
if (!token1.toLong(r)) {
have3ValidNumbers = false;
Serial.print("Red number invalid:");Serial.println(token1);
}
if (!token2.toLong(g)) {
have3ValidNumbers = false;
Serial.print("Green number invalid:");Serial.println(token2);
}
if (!token3.toLong(b)) {
have3ValidNumbers = false;
Serial.print("Blue number invalid:");Serial.println(token3);
}
if (have3ValidNumbers) {
Serial.print("The values are ");
Serial.print(" r:");Serial.print(r);
Serial.print(" g:");Serial.print(g);
Serial.print(" b:");Serial.print(b);
Serial.println();
}
}
void loop() {
}
The output for this input "1,20a,100" is
Green number invalid:20a
The 'standard' toInt() method would have returned 1 20 100 as the result.
For an input like "1,a,50" the 'standard' toInt() method would return 1 0 100
The SafeString toLong() method does more error checking when attempting to convert a string to an integer.
You should also add checks for <0 and >255 to ensure the input is valid range
#cstrutton -Excellent suggestion on using 'indexOf' . it saved me a ton of time for my project. One minor pointer though,
I noticed the thirdvalue did not get displayed (was coming back as ZERO). Upon playing with it little-bit and going through the doc at http://arduino.cc/en/Tutorial/StringIndexOf
I realized, I can use lastIndexOf for the last value.
Here are two lines of modifications that provided correct third value.
int lastCommaIndex = myString.lastIndexOf(',');
String thirdValue = myString.substring(lastCommaIndex+1); // To the end of the string
String myString = "dfsdfgsafhffgsdvbsdvdsvsdvsdsdfdfsdsff|date|recipt|weight|time|date|";
// the setup routine runs once when you press reset:
void setup() {
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
int Index1 = myString.indexOf('|');
int Index2 = myString.indexOf('|', Index1+1);
int Index3 = myString.indexOf('|', Index2+1);
int Index4 = myString.indexOf('|', Index3+1);
int Index5 = myString.indexOf('|', Index4+1);
int Index6 = myString.indexOf('|', Index5+1);
String secondValue = myString.substring(Index1+1, Index2);
String thirdValue = myString.substring(Index2+1, Index3);
String fourthValue = myString.substring(Index3+1, Index4);
String fifthValue = myString.substring(Index4+1, Index5);
String firstValue = myString.substring(Index5+1, Index6);
//Serial.println(Index1);
//
Serial.println(secondValue);
Serial.println(thirdValue);
Serial.println(fourthValue);
Serial.println(fifthValue);
Serial.println(firstValue);
delay(14000);
}
Related
I've got an assignment where I have to sum whole numbers up to 100 digits.
They gave me this struct to represent big numbers (I think there are better ways to represent this, but I'm not allowed to modify it):
typedef struct {
char* string;
int lengthError;
} BigNumber;
Where string is the number itself and lengthError is the length of the number or an error that is a previously defined enum.
I've also have the implementation of the sum function
BigNumber *sum(BigNumber* num1, BigNumber* num2) {
BigNumber* result = malloc(sizeof(BigNumber));
int limit = getLength(num1->lengthError, num2->lengthError);
result->string = malloc(limit);
int digitResult;
int index = limit -1;
int carry = 0;
while(index != -1) {
int d1 = ((int)num1->string[index]) - ((int)'0');
int d2 = ((int)num2->string[index]) - ((int)'0');
digitResult = d1 + d2 + carry;
if (digitResult > 9) {
digitResult = digitResult - 10;
carry = 1;
} else {
carry = 0;
}
itoa(digitResult, &result->string[index], 10); //I think this is the problem
index--;
}
result->string[limit] = '\0';
printf("result: %s\n", result->string);
return result;
}
I haven't finished writing that function, I know there are a lot of flaws in it, but the problem is that I can't get to sum 12 + 12. The result I get is 2.
I thought approaching this problem by picking the lasts character of both numbers, transform them into an int and sum them having in mind the carry digit. After I got the result in digitResult I try to convert it to a char and store it in the corresponding position of the result->string pointer
Once it has finished the operation, I add an \0 at the last position of the result->string.
So the question is, how do I make this operation to work as desired? Debugging the code, I noticed that the first time it stores the first result in result->string, following the example above this would be a number 4, it stores trash in that position instead. In the second addition, I store a number 2 correctly and that's the final result I get in when I print the result.
Your use of the itoa function is a problem (though, as you have also suggested, maybe not the only one).
The itoa function converts its first argument into a null-terminated string - so, as well as writing the character representation of digitResult at the indicated place in the string, it also adds a '\0' character after it. Thus, your string will always be terminated immediately after the last digit you write, and 12 + 12, giving 24 will appear to be just the first character: 2.
What you can do instead is to convert the digit yourself (reversing the operation you used to get the d1 and d2 values), then just directly set the string element to the converted digit.
So, instead of:
itoa(digitResult, &result->string[index], 10);
use:
result->string[index] = (char)(digitResult + '0');
I am trying to take certain number as an input and create an array of same length. I know the array is indexed beginning from 0 to n-1, for the array of length n.
I cannot quite figure out where I made the mistake.
import java.util.Scanner;
public class A {
public static void main(String[] args) {
Scanner read = new Scanner(System.in);
System.out.println("Enter the number of test cases:");
int test = read.nextInt();
String[] name = new String[test];
if (test > 0 && test <= 20) {
System.out.println("Please give " + test + " names:");
for (int i = 0; i < name.length; i++) {
name[i] = read.nextLine();
}
}
}
}
Expectation: for example if the input is 9, an array of size 9
result: if the input is 9, the array creates is of 8
The problem is not with arrays but with read.nextLine(). You can use read.next().
Just use .next() instead of .nextLine(). It only parses the next element of the command line. With this you could also type all names in one line, because the Scanner separates by whitespace characters instead of lines.
See the Java documentation for further information about the two methods. https://docs.oracle.com/javase/8/docs/api/java/util/Scanner.html
The problem is that after the read.nextInt() your position is after the int just before the line end so the first read.nextLine() in the loop will read an empty line.
You can either make a read.nextLine() before the loop or instead of nextInt you can read with nextLine() and cast to int with parseInt() in case you are sure you hit an enter after the int.
E.g. instead of
int test = read.nextInt();
do
int test = Integer.parseInt(read.nextLine());
If you don't want to require enter, then you can change
name[i] = read.nextLine();
to
name[i] = read.next();
I have to write a function to encrypt a message given as a string input using the given encryption key. The function should output the encrypted message as a string to encryptedMessage in the argument list. The function prototype must be as follows: void encryptMessage(char *encryptedMessage, char *message, char *encryptionKey); The function must take the encryption key and convert each of its characters, which represent hexadecimal digits, to their equivalent decimal values as integers. I already wrote a function to convert hex2decimal. The message must then be encrypted by adding the first of these integer values to the ASCII value of the first character in the message, and the second of the integer values to the second character in the message, and so on, and start again with the first integer value after every 16. This will be necessary if the message is longer than the encryption key, which will usually be the case.
here is some of my code so far:
void encryptMessage(char *encryptedMessage, char *message, char *encryptionKey)
{
int *arr = malloc(sizeof(int)*getStringLength(encryptionKey));
int i;
for(i = 0;i < getStringLength(encryptionKey);i++){
arr[i] = hexDigit2Dec(encryptionKey[i]);
message[i] = message[i] + (char)arr[i];
if(getStringLength(message ) > getStringLength(encryptionKey)){
i = 0;
}
}
free(arr);
}
when i run it "project.exe has stopped" pops up. Please help me out, i am new at C and struggling a lot.
You need 2 counters: one for the encryption key position and one for the character being worked on.
You are using one and resetting it to zero whenever the message gets longer than the key causing an infinite loop
for ( keyPos = 0, msgPos = 0; msgPos < getStringLength(message ); ++keyPos, ++msgPos )
{
// calculate and append next char to encrypted message here
if ( keyPos >= getStringLength(encryptionKey)
{
keyPos = 0;
}
}
You'll have to learn to do some planning first and think about what you need to do ... I'll try to give kind of a step by step coding here so hopefully you will see where you went wrong.
But first, there's a standard C function for getting the length of a string: strlen(). I will use this. If you have certain requirements to use something different instead, oh well.
Let's start with the prototype you were given:
void encryptMessage(char *encryptedMessage, char *message, char *encryptionKey)
{
It's a bit ambiguous, but I guess encryptedMessage should be the output. For a real-world project, make it explicit by adding a const to the other pointers. But for now, let's ignore that. As encryptedMessage is a parameter here and not the return value, I assume it's the callers responsibility to provide storage. So, move on ...
You will need the length of your encryptionKey multiple times, let's put it in a variable:
size_t keyLen = strlen(encryptionKey);
And then you need the integer values of the key hex digits multiple times, too, so let's pre-calculate them:
char *keyDigits = malloc(keyLen); // we only need char-sized integers here
for (int i = 0; i < keyLen; ++i)
{
keyDigits[i] = (char)hexDigit2Dec(encryptionKey[i]);
}
Now it's time for the main loop ... you just need to take each character of message and add a value from keyDigits to it:
int keyPos = 0;
for (int i = 0; i < strlen(message); ++i)
{
encryptedMessage[i] = message[i] + keyDigits[keyPos];
if (++keyPos == keyLen) keyPos = 0;
}
And that's it ... free your temporary array and you're done.
free(keyDigits);
}
Sometimes we need to calculate very long number which couldn't hold any numerical data type of C. As we know all common numerical data type has limitation.
I'm beginner and I think... it is possible by string. My question is:
How can I add two strings?
Sample Input:
String 1: 1234
String 2: 1234
Output
Result : 2468
[Note: Numbers can be very very long in Strings. Unlimited]
Do not convert to a number. Instead, add as you (must) have learned in basic eductation: one pair of digits at a time, starting from the lowest (rightmost) and remember to carry the tens forwards (to the left).
The length of the source strings does not matter, but you must be sure the result char array is large enough for the longest input value plus one (optional) digit.
The algorithm is so simple that I will not "type the code" (which is off-topic for Stack Overflow). It boils down to
carryOver = 0
loop:
result0 = inputA0 + inputB0 + carryOver
if result0 > '9'
carryOver = 1
result0 -= 10
else
carryOver = 0
go to loop while there is still input left ...
where the 0 in the variable names indicate the index of the current digits under consideration.
Edit This Answer does not allow carry overs but infinity long add operations. It does not solve the problem of the user. But it is an implementation example and the user asked for one. This is why I will let the answer stay here and not delete it.
You can use atoi (ascii to int)
Do you realy mean C or C++?
This code can't calculate 8+3 = 11 but 5+3 = 8. There is no carry over.
int temp;
const inst size_of_array;
char one[size_of_array];
char two[size_of_array];
char result[size_of_array];
for(int i = 0; i < size_of_array; i++)
{
temp = atoi(one[i]) +atoi(two[i]);
results[i] = numberToCharacter(temp);
}
char numberToCharacter((int temp)
{
if(temp == 1)
{
return('1'):
} ///..
}
Parse the string variables to integer variables. Calculate sum of them, then parse the result to string.
Here is a fiddler.
Here is the code:
#include <stdio.h>
int main(void) {
//Declaring string variables
char string1[10] = "1234";
char string2[10] = "1234";
//Converting them to integer
int int1 = atoi(string1);
int int2 = atoi(string2);
//Summing them
int intResult = int1 + int2;
//Printing the result
printf("%d", intResult);
return 0;
}
I've searched around for a quiet some time but surprisingly I couldn't find an answer to it:
I want to rewrite a char array starting from [0], but all what's happening is: it's always appending. Here's my code:
The algorithm is: I have a very long string which I like to break into several lines (wherever there is a blank space at the end of a line). Each line shall be saved in an array Index (lineContent);
void print_text(char* content, int menu_width, int which_selected, int menu_height, int scroll_pos)
{
int posCounter = 0;
int charCounter = menu_width-10;
int printOutCounter;
char* lineContent[400]; // 400 lines max
short spaceFound;
while (strlen(content) > menu_width) // If string is longer than 1 line
{
//Interesting Part ---------- START
char changeString [strlen(content)];
char printString [menu_width-10];
spaceFound = 0;
charCounter = menu_width-10;
lineContent[posCounter] = malloc(MAXITEMSTR);
while (spaceFound == 0)
{
if (content[charCounter] == ' ')
{
// I guess the error goes between here ...
strncpy(changeString,content,strlen(content));
strncpy(printString,content,menu_width-10);
// ...and here
memmove(&changeString[0], &changeString[charCounter], strlen(content));
content=changeString;
lineContent[posCounter]=printString;
strcat(lineContent[posCounter],"\0");
posCounter++;
spaceFound = 1;
//Interesting Part ---------- END
}
charCounter--;
if (charCounter <= 0)
spaceFound = 1;
}
}
}
As I said, in the end, when checking the content of lineContent, every entry is the same (the one from the last line).
I think this is because, strcpy just appends to the end, therefor I have to clear the array, to erase the former line. So it will start from [0] and not from the last printed letter.
Has anybody an idea how to do this? Is there a function that overwrites a char array instead of appending it?
Kind Regards
Strcat appends to the end, strcpy overwrites the value stored in the string.