C++ How to parse math problem in string using TinyExpr? - visual-c++

First I need to detect if message from player contains math problem
like I get 2 messages from him
char* message1 = "Please solve this math problem";
char* message2 = "How much is 1 + 2 ?";
These messages are not static, player can say different messages.
I need to process message1 and message2
I need to detect math problem and cut it like see message2 and I need it to be "1+2"
char* mathProblemFromMessage = "1+2"; // <- I need to get this from message also detect if message contains any math problem before
double answer = te_interp(mathProblemFromMessage, 0);
printf("Answer is %f\n", answer);
my current code
std::string msg = Message;
if (func.contains_math_operators(msg.c_str()) && func.contains_number(msg.c_str()))
{
double answer = te_interp(Message, 0);
}
I think it fails and always results 0 because msg is "Player: 1+1" I need to cut math problem from it, I dont know how to do it...a

Find a position of the first digit in that string and get a substring from that point:
std::size_t found = msg.find_first_of("0123456789");
if(found != std::string::npos)
{
std::string sub = msg.substr(found);
double answer = te_interp(sub, 0);
}
If that also fails, try to trim invalid tail.
You may want to extend that find_first_of above to include open paren (, unary minus - or some supported function names (I am not familiar with TinyExpr)

Related

String with the same content but comparison always returns false

I have the following code, in which using the WiFi library I perform a scan of the available WiFi networks and want to detect if a specific network is available. I am using ESP32 and Arduino IDE. EEPROM memory handling seems to work, but I don't understand why the comparison always returns zero.
SSID = EEPROM.readString(500); // I read from eeprom the string stored in pos 500
WiFi.mode(WIFI_STA);
delay(100);
Serial.println(logg + "SCAN!");
int n = WiFi.scanNetworks();
Serial.println(logg + "SE DETECTARON: " + String(n) + " REDES WIFI!");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.println("'" + WiFi.SSID(i) + "' vs '" + SSID + "' SizeOf: " + String(WiFi.SSID(i).length()) + " - " + String(SSID.length()) + " Comparacion " + String(WiFi.SSID(i) == SSID );
}
delay(10);
What I get on the serial monitor is the following:
'WRT1900AC 2.4GHz' vs 'WRT1900AC 2.4GHz' SizeOf: 16 - 16 Comparacion 0
The two strings look the same, they are the same size. I already tried replacing comparator "==" with strcmp and I get -244.
I also tried using .c_str as follows:
WiFi.SSID(i).c_str() == SSID.c_str()
but with the same results. If someone comes up with something I would be very grateful.
The two strings look the same, they are the same size.
Although the WiFI.SSID() return a String object, however it does not necessary to be ASCII-encoded. The string encoding is depend on the locale setting of the router, and the reason it looks the same is because the Serial.print() cast it into ASCII. This can be proof by the following sketch by using both Serial.print() and Serial.printf() in ESP32 which shown what is actually received (Serial.printf() however does not support Unicode formatting in ESP32 implementation, so it will produce some garbage characters).
int n = WiFi.scanNetworks();
for (int i=0; i<n; i++) {
// Serial.print() will cast the WiFi.SSID() to ASCII
Serial.print(WiFi.SSID(i));
// this shown what WiFi.SSID() truly return
Serial.printf(" --- %s\n", WiFi.SSID(i));
}
This will produce results in show in this picture. As you can see some SSIDs produce the correct results but some shown up as garbage.
So String comparison operator does do the job correctly when you compare WiFi.SSID(i) == SSID and the result indeed is not necessary equal for some SSID, even though it "looks" the same to human.
So how to solve it? If you want to treat them "as the same", ironically, converting String object to char array with .c_str() does do the job because it convert each char to an ASCII. I guess you just didn't use the char array comparison strcmp() correctly.
if(strcmp(WiFi.SSID(i).c_str(), SSID.c_str()) == 0) {
// match
}
else {
// not match
}
If you are saying that this c.str() comparison return -244, then edit your question and do a Serial.printf() on both String or better off to loop through the String character by charter and print out the HEX code to see what's going on.

Grabbing first number in string after some keyword occurrence in C++ (Arduino)

I have a string coming from PC through serial to a microcontroller (Arduino), e.g.:
"HDD: 55 - CPU: 12.6 - Weather: Cloudy [...] $";
by this function I found:
String inputStringPC = "";
boolean stringCompletePC = false;
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputStringPC += inChar;
if (inChar == '$') // end marker of the string
{
stringCompletePC = true;
}
}
}
I would like to extract the first number of it after the word HDD, CPU and also get the string after Weather (ie "cloudy"); my thinking is something like that:
int HDD = <function that does that>(Keyword HDD);
double CPU = <function that does that>(Keyword CPU);
char Weather[] = <function that does that>(Keyword Weather);
What is the right function to do that?
I looked into inputStringSerial.indexOf("HDD") but I am still a learner to properly understand what it does and don't know if theres a better function.
My approach yielded some syntax errors and confused me with the difference in usage between "String inputStringSerial" (class?) and "char inputStringSerial[]" (variable?). When I do 'string inputStringSerial = "";' PlatformIO complains that "string" is undefined. Any help to understand its usage here is greatly appreciated.
Thanks a bunch.
The String class provides member functions to search and copy the contents of the String. That class and all its member functions are documented in the Arduino Reference:
https://www.arduino.cc/reference/tr/language/variables/data-types/stringobject/
The other way a list of characters can be represented is a char array, confusingly also called a string or cstring. The functions to search and copy the contents of a char array are documented at
http://www.cplusplus.com/reference/cstring/
Here is a simple Sketch that copies and prints the value of the Weather field using a String object. Use this same pattern - with different head and terminator values - to copy the string values of the other fields.
Once you have the string values of HDD and CPU, you'll need to call functions to convert those string values into int and float values. See the String member functions toInt() and toFloat() at
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/toint/
or the char array functions atoi() and atof() at
http://www.cplusplus.com/reference/cstdlib/atoi/?kw=atoi
String inputStringPC = "HDD: 55 - CPU: 12.6 - Weather: Cloudy [...] $";
const char headWeather[] = "Weather: "; // the prefix of the weather value
const char dashTerminator[] = " -"; // one possible suffix of a value
const char dollarTerminator[] = " $"; // the other possible suffix of a value
void setup() {
int firstIndex; // index into inputStringPC of the first char of the value
int lastIndex; // index just past the last character of the value
Serial.begin(9600);
// find the Weather field and copy its string value.
// Use similar code to copy the values of the other fields.
// NOTE: This code contains no error checking for unexpected input values.
firstIndex = inputStringPC.indexOf(headWeather);
firstIndex += strlen(headWeather); // firstIndex is now the index of the char just past the head.
lastIndex = inputStringPC.indexOf(dollarTerminator, firstIndex);
String value = inputStringPC.substring(firstIndex, lastIndex);
Serial.print("Weather value = '");
Serial.print(value);
Serial.println("'");
}
void loop() {
// put your main code here, to run repeatedly:
}
When run on an Arduio Uno, this Sketch produces:
Weather value = 'Cloudy [...]'

Get String Between 2 Strings with Arduino

I am looking for a way to get a String between 2 Strings using Arduino. This is the source String:
Hello, my name is John Doe# and my favourite number is 32#.
The output has to be:
String name = "John Doe"; //Between "name is " and "#"
String favouriteNumber = "32"; //Between "number is " and "#"
How can this be achieved with Arduino?
I am not able to find any information online about this. Those examples for C are not working anyway. I understand that using String is not recommended in Arduino, but I have to do it this way to make things simpler.
By the way, this method of using a '#' to indicate the end of the data is not an ideal way to do it as I would like the input to be more human readable and more natural. Would anyone please suggest another way to do this as well?
Thanks in advance!
Function midString find the substring that is between two other strings "start" and "finish". If such a string does not exist, it returns "". A test code is included too.
void setup() {
test();
}
void loop() {
delay(100);
}
String midString(String str, String start, String finish){
int locStart = str.indexOf(start);
if (locStart==-1) return "";
locStart += start.length();
int locFinish = str.indexOf(finish, locStart);
if (locFinish==-1) return "";
return str.substring(locStart, locFinish);
}
void test(){
Serial.begin(115200);
String str = "Get a substring of a String. The starting index is inclusive (the corresponding character is included in the substring), but the optional ending index is exclusive";
Serial.print(">");
Serial.print( midString( str, "substring", "String" ) );
Serial.println("<");
Serial.print(">");
Serial.print( midString( str, "substring", "." ) );
Serial.println("<");
Serial.print(">");
Serial.print( midString( str, "corresponding", "inclusive" ) );
Serial.println("<");
Serial.print(">");
Serial.print( midString( str, "object", "inclusive" ) );
Serial.println("<");
}
just searched for this and saw no answer so i cooked one up.
i prefer working with String as well because of code readability and simplicity.
for me its more important than squeezing every last drop of juice out of my arduino.
String name = GetStringBetweenStrings("Hello, my name is John Doe# and my favourite number is 32#." ,"name is ","#");
String GetStringBetweenStrings(String input, String firstdel, String enddel){
int posfrom = input.indexOf(firstdel) + firstdel.length();
int posto = input.indexOf(enddel);
return input.substring(posfrom, posto);
}
watch out for the first case its fine, but for the second one you would have to change the second filter sting to "#." so it doesn't use the first occurrence of the #

Error in using indexOf not finding char in Arduino String

I have some code that I have no clue why it isn't working.
The code takes a serial input in the form of "xxx,yyy,zzz", where digits can range from 1 to 3 in each number. Because of an odd quirk in an app, it needs to be read as a char, then converted to a string to be handled. The intention is to split into 3 ints, red green and blue, from "RRR,GGG,BBB".
Now this works fine when I manually define String str (see commented code), but when I go and enter it from the serial console, it doesn't want to work. It seems to be coming from the indexOf(',') part, as while using Serial.print(c1);, I found that when I manually entered a string, it returned an index of the comma, but when I used the serial console, it returned -1 (not found).
And yes, the entered string into the console is in the correct format of "RRR,GGG,BBB", I've confirmed that by printing both phone and str independently.
while (Serial.available() > 0) {
char phone = Serial.read();
String str = String(phone);
//String str = "87,189,183";
int ln = str.length()-1;
int c1 = str.indexOf(','); //first place to cut string
int c2 = str.indexOf(',',c1+1); //second place
red = str.substring(0,c1).toInt();
green = str.substring(c1,c2).toInt();
blue = str.substring(c2,ln).toInt();
Serial.print(red);
Edit: With the Arduino String class, creating a string from a char is returning more than just one character, eleven in fact.
This:
char phone = Serial.read();
String str = String(phone);
will never create a string in str that has more than 1 character, since that's what you say you want.
This is the code for the Arduino's String(char) constructor:
String::String(char c)
{
init();
char buf[2];
buf[0] = c;
buf[1] = 0;
*this = buf;
}
So clearly your code will create a 1-character long string.
Also, beware of using indexes computed on the full string, on substrings later.
I'm try to guess that you are using these serial API http://playground.arduino.cc/Interfacing/CPPWindows.
while (Serial.available() > 0) {
char buf[12];
int len = Serial.ReadData(buf,11);
String str = String(buf);
//String str = "87,189,183";
int ln = str.length()-1;
int c1 = str.indexOf(','); //first place to cut string
int c2 = str.indexOf(',',c1+1); //second place
red = str.substring(0,c1).toInt();
green = str.substring(c1,c2).toInt();
blue = str.substring(c2,ln).toInt();
Serial.print(red);
If you are using other API like http://arduino.cc/en/Serial/Read you should follow these API where Serial is a Stream and read() return just the first available char.
Code was fixed by using a different function.
while (Serial.available() > 0) {
char phone = Serial.read();
str += phone;
//String str = "87,189,183";
int ln = str.length()-1;
int c1 = str.indexOf(','); //first place to cut string
int c2 = str.indexOf(',',c1+1); //second place
red = str.substring(0,c1).toInt();
green = str.substring(c1,c2).toInt();
blue = str.substring(c2,ln).toInt();
Serial.print(red);
I'm not sure why this works, and why before I was getting a string with more than one character. But it works!

Transform char array into String

I have a function that returns a char array and I want that turned into a String so I can better process it (compare to other stored data). I am using this simple for that should work, but it doesn't for some reason (bufferPos is the length of the array, buffer is the array and item is an empty String):
for(int k=0; k<bufferPos; k++){
item += buffer[k];
}
The buffer has the right values and so does bufferPos, but when I try to convert, for example 544900010837154, it only holds 54. If I add Serial.prints to the for like this:
for(int k=0; k<bufferPos; k++){
Serial.print(buffer[k]);
Serial.print("\t");
Serial.println(item);
item += buffer[k];
}
the output is this:
5
4 5
4 54
9 54
0 54
0 54
0 54
1 54
0 54
8 54
3 54
7 54
1 54
What am I missing? It feels like such a simple task and I fail to see the solution...
If you have the char array null terminated, you can assign the char array to the string:
char[] chArray = "some characters";
String String(chArray);
As for your loop code, it looks right, but I will try on my controller to see if I get the same problem.
Three years later, I ran into the same problem. Here's my solution, everybody feel free to cut-n-paste. The simplest things keep us up all night! Running on an ATMega, and Adafruit Feather M0:
void setup() {
// turn on Serial so we can see...
Serial.begin(9600);
// the culprit:
uint8_t my_str[6]; // an array big enough for a 5 character string
// give it something so we can see what it's doing
my_str[0] = 'H';
my_str[1] = 'e';
my_str[2] = 'l';
my_str[3] = 'l';
my_str[4] = 'o';
my_str[5] = 0; // be sure to set the null terminator!!!
// can we see it?
Serial.println((char*)my_str);
// can we do logical operations with it as-is?
Serial.println((char*)my_str == 'Hello');
// okay, it can't; wrong data type (and no terminator!), so let's do this:
String str((char*)my_str);
// can we see it now?
Serial.println(str);
// make comparisons
Serial.println(str == 'Hello');
// one more time just because
Serial.println(str == "Hello");
// one last thing...!
Serial.println(sizeof(str));
}
void loop() {
// nothing
}
And we get:
Hello // as expected
0 // no surprise; wrong data type and no terminator in comparison value
Hello // also, as expected
1 // YAY!
1 // YAY!
6 // as expected
Hope this helps someone!
Visit https://www.arduino.cc/en/Reference/StringConstructor to solve the problem easily.
This worked for me:
char yyy[6];
String xxx;
yyy[0]='h';
yyy[1]='e';
yyy[2]='l';
yyy[3]='l';
yyy[4]='o';
yyy[5]='\0';
xxx=String(yyy);
May you should try creating a temp string object and then add to existing item string.
Something like this.
for(int k=0; k<bufferPos; k++){
item += String(buffer[k]);
}
I have search it again and search this question in baidu.
Then I find 2 ways:
1,
char ch[]={'a','b','c','d','e','f','g','\0'};
string s=ch;
cout<<s;
Be aware to that '\0' is necessary for char array ch.
2,
#include<iostream>
#include<string>
#include<strstream>
using namespace std;
int main()
{
char ch[]={'a','b','g','e','d','\0'};
strstream s;
s<<ch;
string str1;
s>>str1;
cout<<str1<<endl;
return 0;
}
In this way, you also need to add the '\0' at the end of char array.
Also, strstream.h file will be abandoned and be replaced by stringstream

Resources