How to copy front part of string up to a delimiter - c

I need to grab the first part of a string up to and including the last backslash in a path. I am fairly new to C. So I was wondering if the following code is a good approach? Or is there a better way?
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[]) {
char szPath[260] = {0};
strcpy(szPath, argv[0]);
char* p = szPath;
size_t len = strlen(argv[0]);
p+=len; //go to end of string
int backpos = 0;
while(*--p != '\\')
++backpos;
szPath[len-backpos] = 0;
printf("%s\n", szPath);
return 0;
}
After receiving comments changed to this:
char szPath[260];
strcpy(szPath, argv[0]);
/*Scan a string for the last occurrence of a character.*/
char *p = strrchr(szPath, '\\');
if (p) {
*(p + 1) = 0; /* retain backslash and null terminate after that */
} else {
/* handle error */
}
printf("%s\n", szPath);

I would go with strrchr. This assumes str points to writable memory:
char *p;
if ((p = strrchr(str, '\\'))
*(p + 1) = 0; /* Since we passed it to strrchr, it's 0-terminated. */
Obviously, basename and dirname might be there if you are working with paths and might be more appropriate.

Related

How can i add a character after every word in a string?

So what i have is a string(str) that i get from fgets(str, x, stdin);.
If i write for example "Hello World" i want to be able to add a character infront of each word in the string.
To get this "Hello? World?" as an example. I think i've made it alot harder for myself by trying to solve it this way:
add(char *s, char o, char c){
int i, j = 0;
for (i = 0; s[i] != '\0'; i++) {
if (s[i] != o) {
s[j] = s[i];
}
else {
s[j] = c;
}
j++;
}
}
add(str, ' ','?');
printf("\n%s", str);
This will read out "Hello?World" without the spaces. Now the only way i see this working is if i move everything after the first "?" one to the right while also making the positon of the "W" to a space and a "?" at the end. But for much longer strings i can't see myself doing that.
You can't safely extend a string with more characters without insuring the buffer that holds the string is big enough. So let's devise a solution that counts how many additional characters are needed, allocate a buffer big enough to hold a string of that length, then do the copy loop. Then return the new string back to the caller.
char* add(const char* s, char o, char c)
{
size_t len = strlen(s);
const char* str = s;
char* result = NULL;
char* newstring = NULL;
// count how many characters are needed for the new string
while (*str)
{
len += (*str== o) ? 2 : 1;
str++;
}
// allocate a result buffer big enough to hold the new string
result = malloc(len + 1); // +1 for null char
// now copy the string and insert the "c" parameter whenever "o" is seen
newstring = result;
str = s;
while (*str)
{
*newstring++ = *str;
if (*str == o)
{
*newstring++ = c;
}
str++;
}
*newString = '\0';
return result;
}
Then your code to invoke is as follows:
char* newstring g= add(str, ' ','?');
printf("\n%s", newstring);
free(newstring);
#include <stdio.h>
#include <string.h>
int main(void) {
char text[] = "Hello World";
for(char* word = strtok(text, " .,?!"); word; word = strtok(NULL, " .,?!"))
printf("%s? ", word);
return 0;
}
Example Output
Success #stdin #stdout 0s 4228KB
Hello? World?
IDEOne Link
Knowing the amount of storage available when you reach a position where the new character will be inserted, you can check whether the new character will fit in the available storage, move from the current character through end-of-string to the right by one and insert the new character, e.g.
#include <stdio.h>
#include <string.h>
#define MAXC 1024
char *add (char *s, const char find, const char replace)
{
char *p = s; /* pointer to string */
while (*p) { /* for each char */
if (*p == find) {
size_t remain = strlen (p); /* get remaining length */
if ((p - s + remain < MAXC - 1)) { /* if space remains for char */
memmove (p + 1, p, remain + 1); /* move chars to right by 1 */
*p++ = replace; /* replace char, advance ptr */
}
else { /* warn if string full */
fputs ("error: replacement will exceed storage.\n", stderr);
break;
}
}
p++; /* advance to next char */
}
return s; /* return pointer to beginning of string */
}
...
(note: the string must be mutable, not a string-literal, and have additional storage for the inserted character. If you need to pass a string-literal or you have no additional storage in the current string, make a copy as shown by #Selbie in his answer)
Putting together a short example with a 1024-char buffer for storage, you can do something like:
#include <stdio.h>
#include <string.h>
#define MAXC 1024
char *add (char *s, const char find, const char replace)
{
char *p = s; /* pointer to string */
while (*p) { /* for each char */
if (*p == find) {
size_t remain = strlen (p); /* get remaining length */
if ((p - s + remain < MAXC - 1)) { /* if space remains for char */
memmove (p + 1, p, remain + 1); /* move chars to right by 1 */
*p++ = replace; /* replace char, advance ptr */
}
else { /* warn if string full */
fputs ("error: replacement will exceed storage.\n", stderr);
break;
}
}
p++; /* advance to next char */
}
return s; /* return pointer to beginning of string */
}
int main (void) {
char buf[MAXC];
if (!fgets (buf, MAXC, stdin))
return 1;
buf[strcspn(buf, "\n")] = 0;
puts (add (buf, ' ', '?'));
}
Example Use/Output
$ ./bin/str_replace_c
Hello World?
Hello? World?
Look things over and let me know if you have questions.
Just for fun, here's my implementation. It modifies the string in-place and in O(n) time. It assumes that the char-buffer is large enough to hold the additional characters, so it's up to the calling code to ensure that.
#include <stdio.h>
void add(char *s, char o, char c)
{
int num_words = 0;
char * p = s;
while(*p) if (*p++ == o) num_words++;
char * readFrom = p;
char * writeTo = p+num_words;
char * nulByte = writeTo;
// Insert c-chars, iterating backwards to avoid overwriting chars we have yet to read
while(readFrom >= s)
{
*writeTo = *readFrom;
if (*writeTo == o)
{
--writeTo;
*writeTo = c;
}
writeTo--;
readFrom--;
}
// If our string doesn't end in a 'c' char, append one
if ((nulByte > s)&&(*(nulByte-1) != c))
{
*nulByte++ = c;
*nulByte = '\0';
}
}
int main(int argc, char ** argv)
{
char test_string[1000] = "Hello World";
add(test_string, ' ','?');
printf("%s\n", test_string);
return 0;
}
The program's output is:
$ ./a.out
Hello? World?

Remove substring between parentheses in a string

I need to remove each substring between parentheses. I have found some solutions but none is good. Here is an example:
My string is: text(lorem(ipsum)abcd)pieceoftext and the actual output: lorem(ipsum
However, the expected output: text(())pieceoftext or textpieceoftext
Here is the code. I've run out of ideas. I thought of using strtok() but I have two different delimiters.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
const char *s = "text(lorem(ipsum)abcd)pieceoftext";
const char *patternA = "(";
const char *patternB = ")";
char *target = NULL;
char *start, *end;
if (start = strstr( s, patternA ))
{
start += strlen( patternA);
if (end = strstr( start, patternB ) )
{
target = (char *)malloc(end - start + 1);
memcpy(target, start, end - start);
target[end - start] = '\0';
}
}
if (target)
printf("Answer: %s\n", target);
return 0;
}
Looking forward to hearing some of your ideas to solve this problem. Thank you
To begin with, just allocate enough memory to target as you need to hold the entire source string s, because you really have no idea how much space you will need. Remember to add one for the end-of-string character.
Then change patternA and patternB from char * to just char, so you can compare them against individual chars in s.
Then you need to loop through the source string, keeping track of whether you are inside parentheses or not. Since you need to support nested parentheses, I would use a counter of how deep inside the parentheses you are:
int main()
{
const char *s = "text(lorem(ipsum)abcd)pieceoftext";
const char patternA = '(';
const char patternB = ')';
char *target;
int targetIndex = 0;
int parenDepth = 0;
target = malloc(strlen(s) + 1);
// check for malloc() error
for (int sourceIndex = 0; sourceIndex < strlen(s); sourceIndex++) {
if (s[sourceIndex] == patternA) {
// we are going deeper into parens, add to level, then ignore the char
parenDepth++;
continue;
}
if (s[sourceIndex] == patternB) {
// we are coming out of the parens, lower our level, ignore the parens char
parenDepth--;
continue;
}
if (parenDepth == 0) {
// if depth is 0, then we are not inside parens, so copy the char to target
target[targetIndex++] = s[sourceIndex];
}
}
// add end-of-string
target[targetIndex] = '\0';
printf("Answer: %s\n", target);
return 0;
}
I don't understand why you don't use strtok(strtok_r) only. I think it is more functional for this purpose. Just play with it somewhat.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[] = "text(lorem(ipsum)abcd)pieceoftext";
char const * delim = ")(";
char *token;
char *rest = str;
while ((token = strtok_r(rest, delim, &rest))) {
printf("token: %s\n", token);
printf("rest: %s\n", rest);
}
}
You should investigate basic parsing techniques and use those to build a small sized program that does what you want.
hello(world)world
A simple solution:
If lookahead is an opening paren, stop saving. Until there is a closing paren. When there might be imbricated parens you just maintain a global variable of how deep we are (increment when there is an opening paren and decrement when there is a closing paren). When this variable is zero you can save.
You can use the same pattern beforehand to check if there are enough closing parens.

Tokenize a c string

I'm trying to get the string thet's after /xxx/, there is a must be forward slashes, two of them, then the string that I need to extract.
Here is my code, but I don't know where to set the null terminator, there is a math problem here
char str[100] = "/709/usr/datapoint/nviTemp1";
char *tmp;
char token[100];
tmp = strchr(str+1, '/');
size_t len = (size_t)(tmp-str)+1;
strncpy(token, str+len, strlen(str+len));
strcat(token,"\0");
I want to extract whatever after /709/ which is usr/datapoint/nviTemp1
Note that /709/ is variable and it could be any size but for sure there will be two forward slashes.
Simple improvement:
char str[100] = "/709/usr/datapoint/nviTemp1";
char *tmp;
char token[100];
tmp = strchr(str+1, '/');
if (tmp != NULL) strncpy(token, tmp + 1, sizeof(token)); else token[0] = '\0';
tmp points the slash after "/709", so what you want is right after there.
You don't have to calculate the length manually.
Moreover, strncpy copies at most (third argument) characters, so it should be the length of the destination buffer.
If you know for sure that the string starts with `"/NNN/", then it is simple:
char str[100] = "/709/usr/datapoint/nviTemp1";
char token[100];
strcpy(token, str+5); // str+5 is the first char after the second slash.
If you need to get everything after the second slash:
char str[100] = "/709/usr/datapoint/nviTemp1";
char token[100];
char* slash;
slash = strchr(str, '/'); // Expect that slash == str
slash = strchr(slash+1, '/'); // slash is second slash.
strcpy(token, slash+1); // slash+1 is the string after the second slash.
You can use a counter and a basic while loop:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc < 2) return 0;
char *s = argv[1];
char slash = '/';
int slash_count = 0;
while (slash_count < 2 && *s)
if (*s++ == slash) slash_count++;
printf("String: %s\n", s);
return 0;
}
Then you can do whatever you want with the s pointer, like duplicating it with strdup or using strcat, strcpy, etc...
Outputs:
$ ./draft /709/usr/datapoint/nviTemp1
String: usr/datapoint/nviTemp1
$ ./draft /70905/usr/datapoint/nviTemp1
String: usr/datapoint/nviTemp1
You can make use of sscanf-
sscanf(str,"%*[/0-9]%s",token);
/* '/709/' is read and discarded and remaining string is stored in token */
token will contain string "usr/datapoint/nviTemp1" .
Working example

Substrings in the middle of a String in C

I need to extract substrings that are between Strings I know.
I have something like char string = "abcdefg";
I know what I need is between "c" and "f", then my return should be "de".
I know the strncpy() function but do not know how to apply it in the middle of a string.
Thank you.
Here's a full, working example:
#include <stdio.h>
#include <string.h>
int main(void) {
char string[] = "abcdefg";
char from[] = "c";
char to[] = "f";
char *first = strstr(string, from);
if (first == NULL) {
first = &string[0];
} else {
first += strlen(from);
}
char *last = strstr(first, to);
if (last == NULL) {
last = &string[strlen(string)];
}
char *sub = calloc(strlen(string) + 1, sizeof(char));
strncpy(sub, first, last - first);
printf("%s\n", sub);
free(sub);
return 0;
}
You can check it at this ideone.
Now, the explanation:
1.
char string[] = "abcdefg";
char from[] = "c";
char to[] = "f";
Declarations of strings: main string to be checked, beginning delimiter, ending delimiter. Note these are arrays as well, so from and to could be, for example, cd and fg, respectively.
2.
char *first = strstr(string, from);
Find occurence of the beginning delimiter in the main string. Note that it finds the first occurence - if you need to find the last one (for example, if you had the string abcabc, and you wanted a substring from the second a), it might need to be different.
3.
if (first == NULL) {
first = &string[0];
} else {
first += strlen(from);
}
Handle situation, in which the first delimiter doesn't appear in the string. In such a case, we will make a substring from the beginning of the entire string. If it does appear, however, we move the pointer by length of from string, as we need to extract the substring beginning after the first delimiter (correction thanks to #dau_sama).
Depending on your specifications, this may or may not be needed, or another result might be expected.
4.
char *last = strstr(first, to);
Find occurence of the ending delimiter in the main string. Note that it finds the first occurence.
As noted by #dau_sama, it's better to search for ending delimiter from the first, not from beginning of the entire string. This prevents situations, in which to would appear earlier than from.
5.
if (last == NULL) {
last = &string[strlen(string)];
}
Handle situation, in which the second delimiter doesn't appear in the string. In such a case, we will make a substring until end of the string, so we get a pointer to the last character.
Again, depending on your specifications, this may or may not be needed, or another result might be expected.
6.
char *sub = calloc(last - first + 1, sizeof(char));
strncpy(sub, first, last - first);
Allocate sufficient memory and extract substring based on pointers found earlier. We copy last - first (length of the substring) characters beginning from first character.
7.
printf("%s\n", sub);
Here's the result.
I hope it does present the problem with enough details. Depending on your exact specifications, you may need to alter this somehow. For example, if you needed to find all substrings, and not just the first one, you may want to make a loop for finding first and last.
TY guys, worked using the form below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *between_substring(char *str, char from, char to){
while(*str && *str != from)
++str;//skip
if(*str == '\0')
return NULL;
else
++str;
char *ret = malloc(strlen(str)+1);
char *p = ret;
while(*str && *str != to){
*p++ = *str++;//To the end if `to` do not exist
}
*p = 0;
return ret;
}
int main (void){
char source[] = "abcdefg";
char *target;
target = between(source, 'c', 'f');
printf("%s", source);
printf("%s", target);
return 0;
}
Since people seemed to not understand my approach in the comments, here's a quick hacked together stub.
const char* string = "abcdefg";
const char* b = "c";
const char* e = "f";
//look for the first pattern
const char* begin = strstr(string, b);
if(!begin)
return NULL;
//look for the end pattern
const char* end = strstr(begin, e);
if(!end)
return NULL;
end -= strlen(e);
char result[MAXLENGTH];
strncpy(result, begin, end-begin);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *between(const char *str, char from, char to){
while(*str && *str != from)
++str;//skip
if(*str == '\0')
return NULL;
else
++str;
char *ret = malloc(strlen(str)+1);
char *p = ret;
while(*str && *str != to){
*p++ = *str++;//To the end if `to` do not exist
}
*p = 0;
return ret;
}
int main(void){
const char* string = "abcdefg";
char *substr = between(string, 'c', 'f');
if(substr!=NULL){
puts(substr);
free(substr);
}
return 0;
}

Parsing a string with tokens for the first and last words (in C)

I'm going to try to explain the problem.
I am getting a string containing a registry key. For example:
HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey
now, I need to parse that string into 3 different char (or char *) variables. After the parsing it'll be something like:
string1 = HKEY_CURRENT_USER
string2 = \Software\MyProgram\SomeOtherValue\ /* with the '\' */
string3 = SomeKey
Not only do I need to group the backslashes; I also don't know how many of them are there. I could have something like:
HKEY_CURRENT_USER\Software\SomeKey
or something like:
HKEY_CURRENT_USER\Software\SomeValue\SomeOthervalue\Someblah\SomeKey
I tried with strtok() and strcspn() but i'm getting very confused here...
Any idea how to get this done?
Code is appreciated.
Thanks!
Pseudo-Code:
Step 1: Scan forward until the first "\", note the index.
Step 2: Scan Backward from the end to the last "\"
(the first "\" encountered when going backwards), note the index.
Step 3: StrCpy the relevant pieces out into 3 strings.
Code: (does not rely on strrchr, or other methods you seem to have issues with)
void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key);
int main(void)
{
char* regKey = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
char* TopLevel;
char* Path;
char* Key;
ParseRegEntry(regKey, &TopLevel, &Path, &Key);
printf("1: %s\n2: %s\n3: %s\n", TopLevel, Path, Key);
free(TopLevel);
free(Path);
free(Key);
return 0;
}
void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key)
{
int firstDelimiter = 0;
int lastDelimiter = strlen(regKey)-1;
int keyLen;
while(regKey[firstDelimiter] != '\\')
{
firstDelimiter++;
}
while(regKey[lastDelimiter] != '\\')
{
lastDelimiter--;
}
keyLen = strlen(regKey) - lastDelimiter-1;
*TopLevel = (char*)malloc(firstDelimiter+1);
strncpy(*TopLevel, regKey, firstDelimiter);
(*TopLevel)[firstDelimiter] = '\0';
*Path = (char*)malloc(lastDelimiter - firstDelimiter+2);
strncpy(*Path, regKey+firstDelimiter, lastDelimiter - firstDelimiter);
(*Path)[lastDelimiter-firstDelimiter] = '\0';
*Key = (char*)malloc(keyLen+1);
strncpy(*Key, regKey+lastDelimiter+1, keyLen);
(*Key)[keyLen] = '\0';
}
strchr(char*, char) : locate first occurrence of char in string
strrchr(char*, char) : locate last occurrence of char in string
char* str = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char token1[SIZE], token2[SIZE], token3[SIZE];
char* first = strchr(str, '\\');
char* last = strrchr(str, '\\')+1;
strncpy(token1, str, first-str);
token1[first-str] = '\0';
strncpy(token2, first, last-first);
token2[last-first] = '\0';
strcpy(token3, last);
We use strchr to find the first '\', and strrchr to find the last '\'. We then copy to token1, token2, token3 based on those positions.
I decided to just use fixed size buffers instead of calloc-ing, because that's not so important to illustrate the point. And I kept messing it up. :)
Copy the string into an allocated one and split the variable placing a '\0' in the slash where you want to truncate it.
You can "scan" the string for slashes using the strchr function.
void to_split(char *original, int first_slash, int second_slash, char **first, char **second, char **third) {
int i;
char *first_null;
char *second_null;
char *allocated;
if (first_slash >= second_slash)
return;
allocated = malloc(strlen(original) + 1);
*first = allocated;
strcpy(allocated, original);
for (i = 0, first_null = allocated; i < first_slash && (first_null = strchr(first_null,'\\')); i++);
if (first_null) {
*first_null = '\0';
*second = first_null + 1;
}
second_null = allocated + strlen(original);
i = 0;
while (i < second_slash && second_null > allocated)
i += *second_null-- == '\\';
if (++second_null > allocated) {
*second_null = '\0';
*third = second_null + 1;
}
}
Usage:
int main (int argc, char **argv) {
char *toSplit = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
char *first;
char *second;
char *third;
to_split(toSplit, 1, 3, &first, &second, &third);
printf("%s %s %s\n", first, second, third);
return 0;
}
It isn't the best code in the world, but it gives you an idea.
Here's an example using strchr and strrchr to scan forwards and backwards in the string for the '\'.
char str[] = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char *p, *start;
char root[128], path[128], key[128];
p = strchr (str, '\\');
strncpy (root, str, p - str);
start = p;
p = strrchr (str, '\\') + 1;
strncpy (path, start, p - start);
strcpy (key, p);

Resources