Trying to properly substring with String - c++

Given the following function:
If I execute setColor("R:0,G:0,B:255,");
I'm expecting the red, grn, blu values to be:
0 0 255 except I'm getting 0 0 0
It's working fine for R:255,G:0,B:0, or R:0,G:255,B:0, though.
int setColor(String command) {
//Parse the incoming command string
//Example command R:123,G:100,B:50,
//RGB values should be between 0 to 255
int red = getColorValue(command, "R:", "G");
int grn = getColorValue(command, "G:", "B");
int blu = getColorValue(command, "B:", ",");
// Set the color of the entire Neopixel ring.
uint16_t i;
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(red, grn, blu));
}
strip.show();
return 1;
}
int getColorValue(String command, String first, String second) {
int rgbValue;
String val = command.substring(command.indexOf(first)+2, command.indexOf(second));
val.trim();
rgbValue = val.toInt();
return rgbValue;
}

Without knowing your String implementation, I can only make an educated guess.
What happens is that indexOf(second) doesn't give you what you think.
"R:0,G:0,B:255,"
^ ^- indexOf("B:")
|- indexOf(",")
It works for your other cases as none of the things they look for occur more than once in the string.
Looking at the SparkCore Docs we find the documentation for both indexOf and substring.
indexOf()
Locates a character or String within another String. By default, searches from the beginning of the String, but can also start from a given index, allowing for the locating of all instances of the character or String.
string.indexOf(val)
string.indexOf(val, from)
substring()
string.substring(from)
string.substring(from, to)
So now to fix your problem you can use the second variant of indexOf and pass that the index you found from your first search.
int getColorValue(String command, String first, String second) {
int rgbValue;
int beg = command.indexOf(first)+2;
int end = command.indexOf(second, beg);
String val = command.substring(beg, end);
val.trim();
rgbValue = val.toInt();
return rgbValue;
}

In this instance, I would split the string using a comma as the delimiter then parse each substring into a key-value pair. You could use a vector of value for the second part if you always have the sequence "R,G,B" in which case why have the "R:", "G:" or "B:" at all?

I can suppose that command.indexOf(second) will always find you the first comma, therefore for B the val becomes empty string.
Assuming that indexOf is something similar to .Net's, maybe try
int start = command.indexOf(first)+2;
int end = command.indexOf(second, start)
String val = command.substring(start+2, end);
Note the second argument for the second call to indexOf, I think it will make indexOf to look for matches after start. I also think you'd better pass a "," as a second for all calls, and add +1 or -1 to end to compensate for this passing "," instead of "G" and "B".
Or just use another limiter for B part, like R:0,G:0,B:0. (dot instead of comma).

I ended up just modifying my code:
int setColor(String command) {
int commaIndex = command.indexOf(',');
int secondCommaIndex = command.indexOf(',', commaIndex+1);
int lastCommaIndex = command.lastIndexOf(',');
String red = command.substring(0, commaIndex);
String grn = command.substring(commaIndex+1, secondCommaIndex);
String blu = command.substring(lastCommaIndex+1);
// Set the color of the entire Neopixel ring.
uint16_t i;
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(red.toInt(), grn.toInt(), blu.toInt()));
}
strip.show();
return 1;
}
I simply just do: 255,0,0 and it works a treat.

Related

Why PCRE regex only capture 19 groups?

My Question:
My regex pattern is: (a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)(q)(r)(s)(t)(u)(v)(w)(x)(y)(z)
and My string is: abcdefghijklmnopqrstuvwxyz
the code's output is:
i_0:0 i_1:26 i_2:0 i_3:1 i_4:1 i_5:2 i_6:2 i_7:3 i_8:3 i_9:4 i_10:4 i_11:5 i_12:5 i_13:6 i_14:6 i_15:7 i_16:7 i_17:8 i_18:8 i_19:9 i_20:9 i_21:10 i_22:10 i_23:11 i_24:11 i_25:12 i_26:12 i_27:13 i_28:13 i_29:14 i_30:14 i_31:15 i_32:15 i_33:16 i_34:16 i_35:17 i_36:17 i_37:18 i_38:18 i_39:19 i_40:0 i_41:0 i_42:0 i_43:0 i_44:0 i_45:0 i_46:0 i_47:0 i_48:0 i_49:0 i_50:0 i_51:0 i_52:0 i_53:0 i_54:0 i_55:0 i_56:0 i_57:0 i_58:0 i_59:0
Question: Why PCRE regex only capture 19 groups?
My Code
#include <pcre.h>
#include <iostream>
pcre* _rex;
pcre_extra* _rexEx;
void CompileRexStr(const std::string& rex) {
const char* errorinfo;
int errpos = 0;
_rex = NULL;
_rexEx = NULL;
_rex = pcre_compile(rex.c_str(), PCRE_UTF8, &errorinfo, &errpos, NULL);
_rexEx = pcre_study(_rex, PCRE_STUDY_JIT_COMPILE, &errorinfo);
}
int main(){
std::string rex = "(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)(q)(r)(s)(t)(u)(v)(w)(x)(y)(z)";
CompileRexStr(rex);
std::string str = "abcdefghijklmnopqrstuvwxyz";
int result[60] = {0};
int cur = 0;
int pos = pcre_exec(_rex, _rexEx, str.c_str(), str.length(), cur, 0, result, 60);
for(int i=0;i < 60; i++) {
std::cout << "i_" << i << ":" << result[i] << " ";
}
return 0;
}
It returns 19 capture groups, because you provided space to return 20 matches, and one is used for whole matching string
Captured substrings are returned to the caller via a vector of integers whose address is passed in ovector. The number of elements in the vector is passed in ovecsize, which must be a non-negative number. Note: this argument is NOT the size of ovector in bytes.
The first two-thirds of the vector is used to pass back captured substrings, each substring using a pair of integers. The remaining third of the vector is used as workspace by pcre_exec() while matching capturing subpatterns, and is not available for passing back information. The number passed in ovecsize should always be a multiple of three. If it is not, it is rounded down.
Source: Manual for PCRE
If you have 26 capture groups, you need to pass a vector containing (26 + 1)×3 = 81 element at least.

Generate string lexicographically larger than input

Given an input string A, is there a concise way to generate a string B that is lexicographically larger than A, i.e. A < B == true?
My raw solution would be to say:
B = A;
++B.back();
but in general this won't work because:
A might be empty
The last character of A may be close to wraparound, in which case the resulting character will have a smaller value i.e. B < A.
Adding an extra character every time is wasteful and will quickly in unreasonably large strings.
So I was wondering whether there's a standard library function that can help me here, or if there's a strategy that scales nicely when I want to start from an arbitrary string.
You can duplicate A into B then look at the final character. If the final character isn't the final character in your range, then you can simply increment it by one.
Otherwise you can look at last-1, last-2, last-3. If you get to the front of the list of chars, then append to the length.
Here is my dummy solution:
std::string make_greater_string(std::string const &input)
{
std::string ret{std::numeric_limits<
std::string::value_type>::min()};
if (!input.empty())
{
if (std::numeric_limits<std::string::value_type>::max()
== input.back())
{
ret = input + ret;
}
else
{
ret = input;
++ret.back();
}
}
return ret;
}
Ideally I'd hope to avoid the explicit handling of all special cases, and use some facility that can more naturally handle them. Already looking at the answer by #JosephLarson I see that I could increment more that the last character which would improve the range achievable without adding more characters.
And here's the refinement after the suggestions in this post:
std::string make_greater_string(std::string const &input)
{
constexpr char minC = ' ', maxC = '~';
// Working with limits was a pain,
// using ASCII typical limit values instead.
std::string ret{minC};
auto rit = input.rbegin();
while (rit != input.rend())
{
if (maxC == *rit)
{
++rit;
if (rit == input.rend())
{
ret = input + ret;
break;
}
}
else
{
ret = input;
++(*(ret.rbegin() + std::distance(input.rbegin(), rit)));
break;
}
}
return ret;
}
Demo
You can copy the string and append some letters - this will produce a lexicographically larger result.
B = A + "a"

C++ calculator and for loop

string Expression::addevaluate(string x){
stringrep = x; //Stringrep is the string that user typed in,
//it might be 5+6+7-8-9*3/(2+5)
int totalnum = stringrep.length();
for(int i=0;i < totalnum;i++){ //This for loop will seperate the
//string by "+" and output a vector
//with seperate string
int addop = stringrep.find("+");
addvector.push_back(stringrep.substr(0,addop));
string a =stringrep.substr(0,addop);
totalnum=totalnum-(a.length());
stringrep = stringrep.substr(addop+1,totalnum);
}
int vectorlength = addvector.size();
for(int i = 0;i<vectorlength;i++){
cout << i+1<<":"<<addvector[i]<<",";
}
subevaluate(addvector);
return stringrep;
}
string Expression::subevaluate(vector<string> &v){
int totalnum = v.size();
//This is the question, I have no idea how can i set the value totalnum
//If it's the size of vector,it's too small. If it's the last totalnum
//from last function. Then there is a error. In addition,I do not know
//what the error is.
for(int i=0;i < totalnum;i++){
int addop = v[i].find("-");
if(addop > 0){
subtvector.push_back(v[i].substr(0,addop));
string a =v[i].substr(0,addop);
totalnum=totalnum-a.length();
v[i] = v[i].substr(addop+1,totalnum);
}
}
int vectorlength = subtvector.size();
for(int i = 0;i<vectorlength;i++){
cout << i+1<<":"<<subtvector[i]<<",";
}
return stringrep;
}
I do not know why I did wrong for the second for loop. Please help me solve the for loop. In addition,how can i seperate all the string by."+","-","*","/". Then calculate the answer like a calculator. Thanks.
This implementation will not work... suppose you have
"1+2*(3+4)"
the first split (even when written correctly) will get
"1"
"2*(3"
"4)"
What are you going to do with "2*(3" ?
At the very minimum to write a calculator with this approach you need:
add "(" front and add ")" at the end (i.e. change to "(1+2*(3+4))"
look for last OPEN parenthesis
move from there to the first CLOSED parenthesis
process what is in-between (i.e. "3+4") and replace the whole parenthesized expression it in the original string with the result (i.e. get from "1+2*(3+4)" to "(1+2*7)")
repeat until there are no more parenthesis
For splitting a string on a given character you should write a dedicated function, for example:
std::vector<std::string> split(const std::string& text, char sep) {
std::vector<std::string> result;
size_t pos = text.find(sep);
while(pos != std::string::npos) {
result.push_back(text.substr(0, pos));
text = text.substr(pos + 1);
}
result.push_back(text);
return result;
}
then you can write
std::vector<std::string> res = split(text, '+');
to get from "1+2*3+4" to a vector containing "1", "2*3", "4".
PS: Note that this way of computing expression is not what normally is done, but it can be made working so you should in my opinion keep working on it until it's done.
I think it will be difficult to make the code work when you split the string into a vector. The operator precedence will be too hard to handle, I think.
How about a recursive process?
In this way you can simplify the original string step by step. You just keep calling the evaluate function with substrings until they are turned into simple expressions.
Example:
exp = 12/(5+1)
call 1: call f("12/(5+1)")
call 1: f identifies the substring "5+1" and call itself (recursive)
call 2: call f("5+1")
call 2: simple expression calculates into "6" which is returned
call 1: The substring "(5+1)" is replaced by the returned "6"
call 1: exp now looks "12/6"
call 1: simple expression calculates into "2" which is returned
More complex expressions like "48/(5 + (2*3/(3-1))) would just result in more calls so that the string is simplified step by step.
The code could look like the code below. Only the structure is include - it is for OP to fill in the actual code.
bool isSimpleExpression(string& s)
{
// Return true if s is simple, i.e. X+Y, X-Y, X*Y, X/Y
// Otherwise false
}
string evaluateString(string& exp)
{
while(!isSimpleExpression(exp))
{
// exp must be broken into smaller part as it isn't simple yet
if (ExpContainsParanthesis() )
{
// Example: exp is "12/(5+1)"
string s1 = FindSubstringInMostInnerMatchingParanthesis(exp);
// Example: s1 is "5+1"
// Example: call evaluateString("5+1")
strint s2 = evaluateString(s1); // Recursive call
// Example: s2 is 6
ReplaceS1WithS2(exp, s1, s2);
// Example: exp is "12/6"
}
else if (ExpContainsMultiplication())
{
// Find the substring with multiplication
// Call this function with the substring
// Replace the substring with the returned result
}
else if ....
{
// division
}
// ... and so on
}
// Calculate the simple expression
string result;
// ..
// ..
return result;
}

How to remove the final character

The following function will generate a string with '\x' in between,
string GetHexEncode(string hexstring){
string swap = "\\x";
string h = "\\x";
int si = hexstring.length();
for (int i=0; i<hexstring.length(); i++)
{
if (i%2==0){
swap+=hexstring.at(i);
}
else
{
swap+=hexstring.at(i)+h;
}
}
return swap;
}
On occasion, the program outputs the following:
\x45\x39\xD3\x5B\x4F\xEA\x6F\x3C\xBC\x1B\xA0\xF4\xE7\x41\xE5\x8
\x45\x39\xD3\x5B\x4F\xEA\x6F\x3C\xBC\x1B\xA0\xF4\xE7\x41\xE5\x
If this happens, is there any way that I can change the last part into this:
\x45\x39\xD3\x5B\x4F\xEA\x6F\x3C\xBC\x1B\xA0\xF4\xE7\x41\xE5
Start out with an empty swap and append h + digits instead of appending an \x at the end.
additionally you should pre-allocate enough space in swap before starting your result as you know the final length of your result before. This would save reallocations of the string.

Switch every pair of words in a string (“ab cd ef gh ijk” becomes “cd ab gh ef ijk”) in c/c++

Switch every pair of words in a string (“ab cd ef gh ijk” becomes “cd ab gh ef ijk”) in c++ without any library function.
int main(){
char s[]="h1 h2 h3 h4";//sample input
switch_pair(s);
std::cout<<s;
return 0;
}
char * switch_pair(char *s){
char * pos = s;
char * ptr = s;
int sp = 0;//counts number of space
while(*pos){
if(*pos==' ' && ++sp==2){ //if we hit a space and it is second space then we've a pair
revStr_iter(ptr,pos-1);//reverse the pair so 'h1 h2' -> '2h 1h'
sp=0;//set no. of space to zero to hunt new pairs
ptr=pos+1;//reset ptr to nxt word after the pair i.e. h3'
}
pos++;
}
if(sp==1) //tackle the case where input is 'h1 h2' as only 1 space is there
revStr_iter(ptr,pos-1);
revWord(s); //this will reverse each individual word....i hoped so :'(
return s;
}
char* revStr_iter(char* l,char * r){//trivial reverse string algo
char * p = l;
while(l<r){
char c = *l;
*l = *r;
*r = c;
l++;
r--;
}
return p;
}
char* revWord(char* s){//this is the villain....need to fix it...Grrrr
char* pos = s;
char* w1 = s;
while(*pos){
if(*pos==' '){//reverses each word before space
revStr_iter(w1,pos-1);
w1=pos+1;
}
pos++;
}
return s;
}
Input - h1 h2 h3 h4
expected - h2 h1 h4 h3
actual - h2 h1 h3 4h
can any noble geek soul help plz :(((
IMO, what you're working on so far looks/seems a lot more like C code than C++ code. I think I'd start from something like:
break the input into word objects
swap pairs of word objects
re-construct string of rearranged words
For that, I'd probably define a really minimal string class. Just about all it needs (for now) is the ability to create a string given a pointer to char and a length (or something on that order), and the ability to assign (or swap) strings.
I'd also define a tokenizer. I'm not sure if it should really be a function or a class, but for the moment, let's jut say "function". All it does is look at a string and find the beginning and end of a word, yielding something like a pointer to the beginning, and the length of the word.
Finally, you need/want an array to hold the words. For a first-step, you could just use a normal array, then later when/if you want to have the array automatically expand as needed, you can write a small class to handle it.
int Groups = 1; // Count 1 for the first group of letters
for ( int Loop1 = 0; Loop1 < strlen(String); Loop1++)
if (String[Loop1] == ' ') // Any extra groups are delimited by space
Groups += 1;
int* GroupPositions = new int[Groups]; // Stores the positions
for ( int Loop2 = 0, Position = 0; Loop2 < strlen(String); Loop2++)
{
if (String[Loop2] != ' ' && (String[Loop2-1] == ' ' || Loop2-1 < 0))
{
GroupPositions[Position] = Loop2; // Store position of the first letter
Position += 1; // Increment the next position of interest
}
}
If you can't use strlen, write a function that counts any letters until it encounters a null terminator '\0'.