I came across the below code while googling which works great. (Credit to Chaitanya Bhatt # Performancecompetence.com)
The below function searches for the last occurrence of the passed delimiter and saves the remaining part of the input string to the returned output string.
void strLastOccr(char inputStr[100], char* outputStr, char *delim)
{
char *temp, *temp2;
int i = 0;
temp = "";
while (temp!=NULL)
{
if(i==0)
{
temp2 = temp;
temp = (char *)strtok(inputStr,delim);
i++;
}
if(i>0)
{
temp2 = temp;
temp = (char *)strtok(NULL,delim);
}
lr_save_string(temp2,outputStr);
}
}
Basically trying to add two new options to pass in.
Occurrence No: Instead of defaulting to the last occurrence, allowing to specific which occurrence to stop at and save the remaining of the string.
Part of the string to save: (Left, Right) At the moment the string is saving the right side once the delimiter is found. Additional option is intended to allow the user to specify for the left or right side of the delimiter is found.
void strOccr(char inputStr[100], char* outputStr, char *delim, int *occrNo, char *stringSide)
So the question is what are the modifications I need to the above function?
Also is it actually possible to do?
UPDATE
After I kept at it I was able to workout a solution.
As I can't answer my own question for another 6 hours, points will be awarded to who can provide an improved function. Specifically I don't like the code under the comment "// Removes the delim at the end of the string."
void lr_custom_string_delim_save (char inputStr[500], char* outputStr, char *delim, int occrNo, int stringSide)
{
char *temp, *temp2;
char temp3[500] = {0};
int i = 0;
int i2;
int iOccrNo = 1;
temp = "";
while (temp!=NULL) {
if(i==0) {
temp2 = temp;
temp = (char *)strtok(inputStr,delim);
i++;
}
if(i>0) {
temp2 = temp;
temp = (char *)strtok(NULL,delim);
if (stringSide==0) {
if (iOccrNo > occrNo) {
strcat(temp3, temp2);
// Ensure an extra delim is not added at the end of the string.
if (temp!=NULL) {
// Adds the delim back into the string that is removed by strtok.
strcat(temp3, delim);
}
}
}
if (stringSide==1) {
if (iOccrNo <= occrNo) {
strcat(temp3, temp2);
strcat(temp3, delim);
}
}
// Increase the occurrence counter.
iOccrNo++;
}
}
// Removes the delim at the end of the string.
if (stringSide==1) {
for( i2 = strlen (temp3) - 1; i2 >= 0
&& strchr ( delim, temp3[i2] ) != NULL; i2-- )
// replace the string terminator:
temp3[i2] = '\0';
}
// Saves the new string to new param.
lr_save_string(temp3,outputStr);
}
You really only need to make a few modifications. As you begin walking the string with strtok() you can store two variables, char *current, *previous.
As you hit each new token, move 'current' to 'previous' and store the new 'current.' At the end of the string parse look at the value of 'previous' to get the second from last element.
Other options, keep a counter and build a pseudo array using the LoadRunner variable handling mechanism, lr_save_string(token_value,"LR_variable_name_"). You'll need to build your variable name string first of course. When you fall out of the parse action your count variable will likely hold the total number of token elements parsed out of the string and then you can use the (counter-1) index value to build your string.
char foo[100]="";
...
sprint(foo, "{LR_variable_name_%d}",counter-1);
lr_message("My second to last element is %s",lr_eval_string(foo));
There are likely other options as well, but these are the two that jump to mind. Also, I recommend a book to you that I recommend to all that want to brush up on their C (including my brother and my uncle), "C for Dummies." There are lots of great options here on the string processing front that you can leverage in LoadRunner.
Related
So i've seen alot of functions like str_replace(str, substr, newstring) but all of them won't work with numbers so i was wondering if anyone had one that would work with both chars and ints or just int ive been looking everywhere and cant figure out a idea on how to write my own.
my goal exactly is to be able to replace a string with a int value in the string not just string with string
below is the function i use to replace strings and it worked just fine
void strrpc(char *target, const char *needle, const char *replacement)
{
char buffer[1024] = { 0 };
char *insert_point = &buffer[0];
const char *tmp = target;
size_t needle_len = strlen(needle);
size_t repl_len = strlen(replacement);
while (1) {
const char *p = strstr(tmp, needle);
// walked past last occurrence of needle; copy remaining part
if (p == NULL) {
strcpy(insert_point, tmp);
break;
}
// copy part before needle
memcpy(insert_point, tmp, p - tmp);
insert_point += p - tmp;
// copy replacement string
memcpy(insert_point, replacement, repl_len);
insert_point += repl_len;
// adjust pointers, move on
tmp = p + needle_len;
}
// write altered string back to target
strcpy(target, buffer);
}
You can turn an integer into a string by "printing" it to a string:
int id = get_id();
char idstr[20];
sprintf(idstr, "%d", id);
Now you can
char msg[1024] = "Processing item {id} ...";
strrpc(msg, "{id}", idstr);
puts(msg);
But note that the implementation of strrpc you found will work only if the string after replacement is shorter than 1023 character. Also note the the example above could more easily be written as just:
printf("Processing item %d ...\n", get_id());
without the danger of buffer overflow. I don't know what exactly you want to achieve, but perhaps string replacement is not the best solution here. (Just sayin'.)
I'm using the following code to split a char array:
char* Split(char* e, int index) {
index = index -1;
char* v[index +2];
char *p;
int i = 0;
p = strtok(e, ",");
while(p && i < index +2)
{
v[i] = p;
p = strtok(NULL, ",");
i++;
};
// Serial.println(v[0]);
//Serial.println(v[1]);
// Serial.println(v[2]);
return v[index];
};
I'm calling the function like this:
char array[]="1,3,4,55,6,7,66";
Serial.println("array:");
Serial.println(array);
char *out;
out = Split(array,2);
Serial.println("out:");
Serial.println(out);
Serial.println("array:");
Serial.println(array);
out = Split(array,2);
Serial.println("out:");
Serial.println(out);
The first time I call the function, everythin is fine. The result I get is "3" , and that is what I expect.
But with the second call of the function, things goes crazy, and I get just some hieroglyphics.
When I check the variables with the Serial output, I can see that "array" is the second time just "1", and this might be the reason of the curious output of the function.
But I don't understand how the first call of the function can affect the value of "array", because this variable is not touched in the function.
Can anybody help me with clarifying this issue?
The output of the serial interface is lke this:
array:
1,3,4,55,6,7,66
out:
3
array:
1
out:
⸮}⸮a⸮⸮-:⸮⸮⸮m⸮⸮⸮⸮⸮⸮⸮]⸮ʻ⸮T⸮;⸮⸮⸮N}⸮⸮⸮⸮{R⸮U)⸮⸮⸮[G⸮⸮`j⸮⸮⸮⸮⸮v⸮⸮wz⸮⸮s⸮⸮⸮⸮⸮⸮}⸮⸮2⸮⸮vz~⸮⸮⸮⸮O}⸮⸮⸮/⸮⸮nv⸮⸮^j⸮yO⸮7{⸮⸮⸮⸮z⸮Z⸮⸮⸮⸮⸮⸮⸮7[⸮⸮⸮j⸮w⸮⸮⸮⸮⸮⸮⸮w)⸮⸮c⸮⸮}⸮⸮⸮⸮⸮⸮⸮⸮⸮v⸮⸮⸮m/V⸮ys<⸮⸮ٿ⸮⸮⸮׆⸮+>ֻ⸮z6⸮=⸮D⸮⸮⸮⸮~⸮⸮⸮⸮e⸮⸮?⸮=⸮⸮W⸮⸮⸮⸮}⸮e⸮ߣN绮⸮w⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮w⸮⸮⸮⸮?⸮⸮⸮⸮⸮⸮⸮Y⸮⸮f⸮v⸮⸮u⸮p?⸮⸮^h⸮⸮}⸮⸮ݼ⸮^Wo⸮⸮⸮⸮⸮_⸮⸮⸮⸮⸮⸮;s⸮⸮⸮⸮wZ⸮⸮⸮~⸮7⸮⸮⸮r⸮⸮⸮⸮)⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮f⸮⸮O⸮⸮⸮⸮⸮⸮⸮⸮⸮
⸮⸮7⸮⸮a.⸮⸮.kG⸮⸮8⸮⸮⸮⸮⸮⸮⸮⸮U⸮⸮⸮⸮⸮⸮⸮⸮⸮'⸮we⸮⸮⸮M⸮{⸮⸮Lu⸮no⸮⸮⸮>⸮⸮⸮⸮⸮⸮⸮~}⸮⸮⸮⸮⸮⸮⸮⸮y⸮⸮o⸮⸮⸮,'>}⸮⸮⸮+⸮X⸮⸮⸮/⸮⸮ױ⸮⸮⸮⸮̲⸮⸮-_M⸮⸮⸮⸮L~⸮#Φz~⸮⸮⸮⸮?⸮⸮⸮⸮⸮{/⸮_⸮:⸮jmc⸮m]S⸮_3⸮>o⸮⸮ݸv⸮⸮⸮|⸮
⸮⸮{_^⸮⸮o⸮?⸮⸮⸮⸮⸮⸮_⸮⸮⸮⸮{⸮⸮⸮^⸮⸮⸮⸮⸮⸮⸮⸮⸮ퟺ⸮⸮߿⸮⸮p⸮⸮⸮w?=⸮⸮⸮X⸮⸮⸮⸮⸮⸮_⸮oy⸮⸮M⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮w⸮⸮⸮[⸮⸮o⸮⸮⸮⸮7wE~⸮⸮⸮⸮⸮N⸮⸮o⸮x⸮=v/⸮⸮⸮⸮>⸮9⸮⸮ί⸮Y_Q⸮⸮l⸮⸮}'⸮⸮}⸮?⸮⸮ޭ⸮6⸮7⸮{⸮T⸮⸮⸮ ⸮r⸮⸮⸮⸮⸮⸮⸮
ܽ+'⸮⸮⸮⸮G⸮f⸮z⸮Gn⸮⸮n⸮/⸮⸮⸮⸮/⸮⸮⸮⸮Q⸮⸮⸮⸮⸮o⸮;⸮L⸮⸮r⸮⸮⸮⸮n/߿ſ⸮⸮⸮⸮q⸮⸮⸮ݮ⸮⸮⸮⸮⸮⸮+⸮⸮⸮⸮⸮⸮ﷹln?⸮⸮⸮⸮q⸮⸮⸮{⸮⸮⸮⸮⸮⸮⸮q⸮-⸮⸮{(⸮⸮f⸮⸮{⸮v⸮܀⸮oq⸮⸮⸮⸮⸮⸮߽⸮⸮nj⸮⸮⸮os⸮6۟g⸮⸮⸮⸮"⸮⸮7Z7⸮⸮yo⸮ӟ⸮⸮⸮w⸮⸮⸮⸮⸮⸮{⸮⸮⸮Vr⸮⸮]_⸮SS⸮_⸮w⸮⸮⸮wl⸮⸮⸮⸮P⸮⸮z⸮⸮m{⸮⸮⸮ݛs⸮(⸮⸮r⸮⸮˷:⸮%⸮⸮⸮⸮Z⸮⸮⸮m⸮W⸮⸮⸮⸮ם*⸮⸮⸮[>⸮⸮⸮/⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮?⸮⸮⸮⸮|⸮.⸮⸮⸮{⸮⸮⸮ꍥ⸮⸮⸮|⸮⸮⸮⸮⸮⸮⸮⸮⸮7~Ls⸮!⸮⸮⸮⸮⸮{⸮x⸮g⸮⸮|֍om~~⸮⸮⸮{⸮cϠ⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮>;⸮W⸮⸮⸮⸮⸮⸮⸮⸮q⸮⸮[:⸮'⸮#⸮o⸮⸮_⸮uϾ⸮⸮⸮⸮[⸮⸮^⸮⸮⸮n⸮}⸮⸮⸮⸮⸮>/⸮_⸮⸮-⸮⸮⸮⸮s⸮⸮⸮}⸮⸮⸮⸮/⸮[w⸮⸮r⸮⸮_⸮⸮⸮⸮,⸮⸮ݯ⸮⸮⸮7ÿ⸮:⸮⸮⸮⸮Ί⸮⸮⸮⸮⸮t[|⸮⸮w⸮F⸮⸮⸮
Has anybody a better idea?
The solution depend on your data, if your data is always like a string with list of integers separated with ,, then it will probably better to split it into an int array, you can then write a generic split() function.
#define NUMBER_OF_ELEMENT 7
int splitted[NUMBER_OF_ELEMENT];
const char* delimiter = ",";
void split(const char *str, const char *delimiter) {
char temp[strlen(str)+1] = {0};
memcpy(temp, str, strlen(str));
int i=0;
char *p = strtok(temp, delimiter);
while(p != NULL) {
splitted[i++] = atoi(p);
p = strtok(NULL, delimiter);
}
}
int setup() {
char array[]="1,3,4,55,6,7,66";
Serial.begin(115200);
split(array, delimiter);
// get every splitted element as an int
for (int i=0; i<NUMBER_OF_ELEMENT, i++) {
Serial.print("Out:");
Serial.println(splitted[i]);
}
//if you really want to have string as result
Serial.println(String(splitted[3]));
}
OK I got it by making the array independent from change by strtok:
void setup(){
Serial.begin(115200);
char array[]="1,3,4,55,6,7,66";
char *out;
char array2[8];
strcpy(array2,array);
Serial.println("array2:");
Serial.println(array2);
out = Split(array2,2);
Serial.println("out:");
Serial.println(out);
Serial.println("array3:");
char array3[8];
strcpy(array3,array);
Serial.println(array3);
out = Split(array3,2);
Serial.println("out:");
Serial.println(out);
}
Not that elegant, but it works!!
Has anybody a better idea?
Thanks,great!
Yes my data is always int. So your function is perfect for me.
But for the sake of a clear structure, I would prefer to work with a return value, instead of changing the global variable "splitted".
Is that a good practice? Or do you prefer your variant for saving RAM?
Here my final solution for this task. The function just returns a single value, according to the given index:
int splitStrToInt(char *str, int index) {
//******************
//This function splits a string that is separated by commas and converts the values to int,
//according to the given index
//caution!! The string may only consist of numerical values !!
//Example: "1,3,4,55,6,7,66"
//******************
index--;
char e[strlen(str) + 1] = { 0 };
memcpy(e, str, strlen(str));
int v[index + 2];
char *p;
int i = 0;
p = strtok(e, ",");
while (p && i < index + 2) {
v[i] = atoi(p);
p = strtok(NULL, ",");
i++;
}
;
return v[index];
}
I'm pretty new to C and was wondering if I could get some help! I've been working on this bug for +15 hours.
So, this program is a tokenizer.
Basically, the program is supposed to take a string, or "token stream," and break it up into "tokens." A "token" is a string of either a word, hexadecimal int, octal int, decimal int, floating point int, or symbol.
The code I'm posting is only the code where things go wrong, the other portion of my program is what creates the token.
The gist of how the below code works is this: It takes a "token stream", and then finds the next token from that stream. Once that is completed, it will create a substring of the "token stream" minus the new token, and return that as the new "token stream."
Essentially, when the string "0x4356/*abdc 0777 */[]87656879jlhg kl(/j jlkh 'no thank you' /" is passed through, the program will do everything properly except when "jlhg kl(/j jlkh 'no thank you' /" passes. Once that passes through my program, a "jlhg" token is created BUT then it is added to the end of the token stream again. So, the new token stream to be broken down becomes " kl(/j jlkh 'no thank you' / jlhg" where jlhg is added on at the end, where it wasn't there before. It does this same weird thing once more, right afterwards, but with "kl" instead.
It only does this under extremely weird conditions, so I'm not sure the cause. I put print statements throughout my program and things flow normally except seemingly out of no where, the program will just add those at the end. This I why I feel like it might be a memory problem, but I have absolutely no clue where to go from here.
Any help would be GREATLY appreciated!!!!
EDIT: If you pass the string "array[xyz ] += pi 3.14159e-10 A12B" output should be:
word "array"
left brace "["
word "xyz"
right brace "]"
plusequals "+="
word "pi"
float "3.14159e-10"
word "A12B"
My TokenizerT is this:
struct TokenizerT_
{
char *tokenType;
char *token;
};
typedef struct TokenizerT_ TokenizerT;
Relevant code:
/*
* TKNewStream takes two TokenizerT objects.
* It will locate the index of the end of the last token,
* and create a substring with the new string to be tokenized.
* #tokenStream: old token stream
* #newToken: new token created from old token stream
*
*/
char *TKGetNextStream(char *tokenStream, char *newToken)
{
int i,
index = 0,
count = 0;
char last = newToken[strlen(newToken)-1];
for(i = 0; i < strlen(newToken); i++)
{
if(newToken[i] == last)
{
count++;
}
}
for(i = 0; i < strlen(tokenStream); i++)
{
if(tokenStream[i] == last && count == 1)
{
index = i + 1;
break;
}
else if(tokenStream[i] == last)
{
count--;
}
}
char *ret = malloc(sizeof(char)*(strlen(tokenStream) - index));
for(i = 0; i < strlen(tokenStream) - index; i++)
{
ret[i] = tokenStream[i+index];
}
return ret;
}
/*
* This is my main
*/
int main(int argc, char **argv)
{
char *string = "0x4356/*abdc 0777 */[]87656879jlhg kl(/j jlkh 'no thank you' /";
TokenizerT *newToken = malloc(sizeof(struct TokenizerT_)),
*tokenStream = malloc(sizeof(struct TokenizerT_));
tokenStream->token = string;
while(newToken != NULL)
{
newToken = TKCreate(TKGetNextToken(tokenStream));
if(newToken != NULL)
{
tokenStream->token = TKGetNextStream(tokenStream->token,
newToken->token);
printf("%s \"%s\"\n",
newToken->tokenType,
newToken->token);
}
}
TKDestroy(newToken);
return 0;
}
The string created in ret isn't properly null terminated. So all the functions dealing with strings will assume it goes on until the next random zero byte that happens to be found after the allocated memory.
To fix this allocate one more byte of space for ret and set that to zero, or use an existing function like strdup() to copy the string:
ret = strdup(tokenStream + index);
Beginner here,
somewhat confused about an exercise:
Tutorial Last one on the page (it is german). I should read HTML-Lines and print attributes and their values. The declaration of the function which should be used is given.
Two things irritate me:
1. The Line is stored in a const char string, but i would like the User to type in his desired HTML-line. It seems not to be possible to change a const variable at runtime. How can it be achieved without changing the given declaration?
2. The Tutorial wants me to give back the position of strtok-search as an integer, but I read online that this value is stored within strtok, is there a way to cast that, or get it somehow?
To solve the exercise I wrote this code, but the program crashes at runtime with "Segmentation fault (core dumped)"-Message and I don't know why, could someone please explain that to me? (I probably need malloc, but for which variable?)
//cHowTo Uebung Teil 2 Nr. 4
//HTMLine.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//char getHTMLline ();
int getHtmlAttributes(const char *string, int start, char *attrNamem,char *attrValue); //given by Tutorial
int main(int argc, char *argv) //because i want user-input later on, if possible
{
const char strg[]= {"<img src=\"kurt.jpg\" width=\"250\" alt=\"Kurt Kanns\" />"}; //given example line by tutorial
char attriN[255]={0}, attriV[255]={0};
int pos=99;
//printf("Please type the tag for analysis.\n");
//fgets(strg, 255, stdin);
printf("attribute\tvalue\n\n");
do
{
pos = getHtmlAttributes(strg, pos, attriN, attriV); //pos should be strtok-search-position
printf("%s\t\t%s\n", attriN, attriV);
}
while(pos!=1);
return EXIT_SUCCESS;
}
int getHtmlAttributes(const char *string, int start, char *attrNamem, char *attrValue)
{
int i, len;
char *ptr;
len = strlen(string);
char stringT[len]; //variable used to be split by strtok
for(i=0; i<len; i++)
stringT[i]=string[i];//copy string to stringT
if(start==99)
ptr = strtok(stringT, "<="); //get first attribute as whole
else
ptr = strtok(NULL, "= "); // get following attributes
for(i=0; i<len; i++)
attrNamem[i] = ptr[i];
ptr = strtok(NULL, "\""); //get values
for(i=0; i<len; i++)
attrValue[i] = ptr[i];
if(ptr == NULL) //if search complete
{
return 1;
}
else // if search continues
{
return 0;
}
}
//char getHTMLline ()
//{
// char user_input;
// scanf("%s", &user_input);
// return user_input;
//}
What strtok() does is that if you call it with a string different to NULL it stores a pointer to that string internally and returns the first token. A subsequent call with NULL then uses that internally stored pointer to determine the next token.
Now what happens in your code is:
When you call getHtmlAttributes() for the first time you create a copy of the given string in stringT and pass that copy to strtok(). The next time you call strtok( NULL, ... ). And there we have two bugs:
your loop to copy string() to stringT() is not correct. You don't copy
the teminating '\0'. Just use strcpy() in such cases
the important one: When you call getHtmlAttributes() for the second time, you call strtok( NULL, ... ) but the lifetime of the stringT that it has been called with originally has ended with the first call of getHtmlAttributes() returning, because stringT is a local variable that is created anew on the stack every time the function is called. You could solve that problem by either
declaring static char stringT[N] where N must be a constant (like 255), you can't use len (what should have been len+1 anyway) in that case
creating a dynamically allocated copy of string by char *stringT = strdup( string );. Please do that only if you call strtok( stringT, ... ) aferwards and be aware that without additional code you have a memory leak because you are not able to free that memory again.
what I would pefer: use string directly instead of stringT. In that case you should not declare string as const and create a copy of strg in main() that you pass to the function
Edit
I think the request "give back the position of strtok-search as an integer" means, you should return the offset of the found token in the complete string. That's quite easy to achieve, if you use the suggested solution static char stringT[N] from above:
As strtok() works on the string passed by the first call, after receiving a ptr different from NULL, you can calculate and return int offset = ptr - stringT;
Edit 2
And now something completely different
I've just read the Tutorial you have linked to (greetings from Hessen :-) ) and I think the idea is to use a new strtok() loop every time the function is called. That could like this:
int getHtmlAttributes(const char *string, int start, char *attrName, char *attrValue)
{
char *buf;
char *attrptr;
char *ptr;
// copy the substring starting at start to buf
// you should add error checking (buf may become NULL)
buf = strdup( string+start );
// first step: tokenize on whitespace; we stop at the first token that contains a "="
for( attrptr = strtok( buf, " \t" ); attrptr && (ptr = strchr( attrptr, '=' )) != NULL; attrptr = strtok( NULL, " \t" ) ) ;
if( attrptr ) {
// copy everything before "=" to attrName
sprintf( attrName, "%.*s", ptr-attrptr, attrptr );
// copy everything after "=" to attrValue
strcpy( attrValue, ptr+1 );
// the next start is the current start + the offset of the attr found
// + the length of the complete attr
start += (attrptr - buf) + strlen( attrptr );
free( buf );
return start;
} else {
// no more attribute
free( buf );
return -1;
}
}
I am currently trying to iterate over a string to find the first white space.
I want to copy all of the characters before that white space into a different string.
Here I am coping more of my code: lineArray is global, and is filled in by a different function which I didn't copy.
char *lineArray[16];
int startProcesses(int background) {
int i = 0;
int var = 0;
int pid;
int status;
int len;
char copyProcessName[255];
while(*(lineArray+i) != NULL) {
len = strlen(lineArray[i]);
for (var = 0; var < len; ++var) {
if(lineArray[i][var] != ' ') {
copyProcessName[var] = lineArray[i][var];
} else {
break;
}
}
I know this is not finished and I am missing '\0', but before that I have noticed on debug that after the first time the compiler tries the copyProcessName[var] = lineArray[i][var]; assignment, the whole string which is in lineArray[i] is destroyed and instead of for example containing ls -l it is replaced with ll - l.
I will mention a few more thins:
lineArray is a global variable, I did try using strcpy but it caused the same destruction so this is the reason I chose to implement it, last thing is that I am using ubuntu.
Does anyone have an idea why is doing that?
Thanks!
I am currently trying to iterate over a string to find the first white space.
Cool.
char s[] = "line with spaces";
char *p = strchr(s, ' '); // pointer to the first WS, if you need it
ptrdiff_t n = p - s; // or its position within the string, if that's what you're looking for