Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
struct configurations *read_file(char * file_name)
{
FILE *f = fopen(file_name ,"r");
if(!f)
{
printf("**********Unable to open config.txt*********");
return NULL;
}
int i, prev, count;
char *line = NULL, buff[480] = {'\0'};
size_t len;
struct configurations *config = (struct configurations *) malloc(sizeof(struct configurations));
while (getline(&line,&len,f) != -1)
{
if(!strncmp("SERVERPORT = ",line,strlen("SERVERPORT = "))){
config->server_Port = atoi(strstr(line, " = ")+3);
}
else if(!strncmp("SCHEDULING = ",line,strlen("SCHEDULING = "))){
strcpy(config->sched,strstr(line, " = ") + 3);
}
By subctracting 1 from the length.
There are multiple simple and obvious improvements to your code
You should always check the return value before using from strstr().
strlen("SERVERPORT = ") is a very ugly way of writing 12, inefficient too.
You should use a little bit more white spaces to make the code readable.
Don't cast the return value of malloc() it only makes it more difficult to read and might hide a bug if you forget to include stdlib.h.
ALWAYS check if malloc() returned NULL before dereferencing the pointer.
Split every line at =, remove all surrounding white spaces from the 2 resulting values and then check which variable it is and assign the corresponding value.
As it is your code will fail if SERVERPORT=1234 for example, and even if it's ugly and spaces around the = operator are better, both should be valid unless of course you explicitly want the spaces.
Also by removing surrounding white spaces you ensure that any '\n' that was read by getline() will be removed from the value.
This is a quick API a wrote just now to show you how I would do it, of course every one has their own taste and ways to do things, but I hope it helps figuring out your mistakes
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct KeyValue {
char *key;
char *value;
};
struct KeyFile {
size_t size;
struct KeyValue *entries;
size_t count;
};
static struct KeyFile *
keyfile_new(void)
{
struct KeyFile *kf;
kf = malloc(sizeof(*kf));
if (kf == NULL)
return NULL;
kf->entries = malloc(10 * sizeof(*kf->entries));
if (kf->entries == NULL) {
kf->size = 0;
} else {
kf->size = 10;
}
kf->count = 0;
return kf;
}
static int
keyfile_add_value(struct KeyFile *kf, const char *const key, const char *const value)
{
struct KeyValue *entry;
if (kf->count + 1 >= kf->size) {
void *pointer;
pointer = realloc(kf->entries, (kf->size + 10) * sizeof(*kf->entries));
if (pointer == NULL)
return -1;
kf->entries = pointer;
kf->size += 10;
}
entry = &kf->entries[kf->count++];
entry->key = strdup(key);
entry->value = strdup(value);
return 0;
}
static void
keyfile_free(struct KeyFile *kf)
{
for (size_t i = 0 ; i < kf->count ; ++i) {
struct KeyValue *entry;
entry = &kf->entries[i];
free(entry->key);
free(entry->value);
}
free(kf->entries);
free(kf);
}
static struct KeyFile *
keyfile_read(const char *const path)
{
FILE *file;
struct KeyFile *kf;
size_t length;
char *line;
line = NULL;
length = 0;
file = fopen(path, "r");
if (file == NULL)
return NULL;
kf = keyfile_new();
if (kf == NULL)
return NULL;
while (getline(&line, &length, file) > 0) {
char *op;
char *key;
char *value;
op = strchr(line, '=');
if (op == NULL) {
fprintf(stderr, "malformed line!\n");
} else {
*op = '\0';
key = line;
while (isspace((unsigned char) *key) != 0)
++key;
value = op + 1;
op -= 1;
while (isspace((unsigned char) *op) != 0)
*(op--) = '\0';
while (isspace((unsigned char) *value) != 0)
value += 1;
op = value + strlen(value) - 1;
while (isspace((unsigned char) *op) != 0)
*(op--) = '\0';
if (keyfile_add_value(kf, key, value) != 0)
goto error;
}
}
fclose(file);
free(line);
return kf;
error:
keyfile_free(kf);
fclose(file);
free(line);
return NULL;
}
static void
keyfile_display(const struct KeyFile *const kf)
{
for (size_t i = 0 ; i < kf->count ; ++i) {
const struct KeyValue *entry;
entry = &kf->entries[i];
fprintf(stdout, "/%s/ => /%s/\n", entry->key, entry->value);
}
}
You could improve this to add lookup functions, to find specific values in the settings file. And you can make it a standalone library to use it in many projects too.
I got the following string from the user:
char *abc = "a234bc567d";
but all the numbers can have different lengths than in this example (letters are constants).
How can I get each part of numbers? (again, it can be 234 or 23743 or something else..)
I tried to use strchr and strncpy but I need to allocate memory for this (for strncpy), and I hope there is a better solution.
Thanks.
You can do something like this:
char *abc = "a234bc567d";
char *ptr = abc; // point to start of abc
// While not at the end of the string
while (*ptr != '\0')
{
// If position is the start of a number
if (isdigit(*ptr))
{
// Get value (assuming base 10), store end position of number in ptr
int value = strtol(ptr, &ptr, 10);
printf("Found value %d\n", value);
}
else
{
ptr++; // Increase pointer
}
}
If I understand your question, you are trying to extract the parts of the user input that contain numbers ... and the sequence of numbers can be variable ... but the letters are fixed i.e. a or b or c or d. Correct ... ? The following program may help you. I tried it for strings "a234bc567d", "a23743bc567d" and "a23743bc5672344d". Works ...
int main()
{
char *sUser = "a234bc567d";
//char *sUser = "a23743bc567d";
//char *sUser = "a23743bc5672344d";
int iLen = strlen(sUser);
char *sInput = (char *)malloc((iLen+1) * sizeof(char));
strcpy(sInput, sUser);
char *sSeparator = "abcd";
char *pToken = strtok(sInput, sSeparator);
while(1)
{
if(pToken == NULL)
break;
printf("Token = %s\n", pToken);
pToken = strtok(NULL, sSeparator);
}
return 0;
}
My search here got many results, but none quite like so that I could find a solution to my problem.
I'm creating a Mathcad UserEFI DLL in C using Visual Studio 2013. I don't want to use strings, only char*.
Now, I want to emulate the console main function, which uses char* argv[] to access the parameters of a called executable. Mathcad will call the DLL with a string like "-T=3 z h 13". All I want is to parse this text into an array of char*, just like argv[] would be if I called an executable with this added parameters. I hope I expressed this in an understandable way.
I use strtok_s to parse the text and one has to consider, that every token can have a different size.
The error must lie in the following function:
typedef struct tArgReturnType {
int ACount;
char** Argus;
} ARGRETURN;
ARGRETURN ParseStringToArgs(char* text) {
char *token = NULL;
char *nextToken = NULL;
int argCount = 0;
char* temptext = NULL;
strcpy(temptext, text);
char** uebergabe = (char**)malloc(sizeof(char**));
token = strtok_s(temptext, " ", &nextToken);
while (token != NULL) {
argCount++;
uebergabe = (char**)realloc(uebergabe, sizeof(uebergabe)+sizeof(token));
uebergabe[argCount - 1] = token;
token = strtok_s(NULL, " ", &nextToken);
}
ARGRETURN ReturnVar;
ReturnVar.ACount = argCount;
ReturnVar.Argus = (char**)malloc(sizeof(uebergabe));
memcpy(ReturnVar.Argus, uebergabe, sizeof(uebergabe));
free(uebergabe);
return ReturnVar;
}
I'm sure that this is a complete mishmash of heap memory allocation failures (as indicated by the error the mathcad compiler gives me), since I modified this code multiple times while trying to find a solution. I'm just utterly confused now.
Updated Code:
typedef struct tArgReturnType {
int ACount;
char** Argus;
} ARGRETURN;
ARGRETURN ParseStringToArgs(char* text) {
char *token = NULL;
char *nextToken = NULL;
int argCount = 0;
char* temptext = malloc(strlen(text) + 1);
strcpy(temptext, text);
char** uebergabe = malloc(sizeof(char**));
token = strtok_s(temptext, " ", &nextToken);
while (token != NULL) {
argCount++;
uebergabe = (char**)realloc(uebergabe, sizeof(uebergabe)+sizeof(token));
uebergabe[argCount - 1] = token;
token = strtok_s(NULL, " ", &nextToken);
}
ARGRETURN ReturnVar;
ReturnVar.ACount = argCount;
ReturnVar.Argus = malloc(sizeof(uebergabe));
memcpy(ReturnVar.Argus, uebergabe, sizeof(uebergabe));
free(uebergabe);
free(temptext);
return ReturnVar;
}
ARGRETURN ParseStringToArgs(const char* text) {
ARGRETURN ReturnVar = { 0 };
int n = 0;
char temp[100];
while (sscanf(text += n, "%99s%n", temp, &n) == 1) {
ReturnVar.Argus = realloc(ReturnVar.Argus, ++ReturnVar.ACount*sizeof(*ReturnVar.Argus));
strcpy(ReturnVar.Argus[ReturnVar.ACount - 1] = malloc(strlen(temp) + 1), temp);
}
return ReturnVar;
}
'sizeof(text)' is a great mistake
don't use ugly strtok(_s), it's not reentrant, destroys the string, ...
use sscanf instead
Given a (char *) string, I want to find all occurrences of a substring and replace them with an alternate string. I do not see any simple function that achieves this in <string.h>.
The optimizer should eliminate most of the local variables. The tmp pointer is there to make sure strcpy doesn't have to walk the string to find the null. tmp points to the end of result after each call. (See Shlemiel the painter's algorithm for why strcpy can be annoying.)
// You must free the result if result is non-NULL.
char *str_replace(char *orig, char *rep, char *with) {
char *result; // the return string
char *ins; // the next insert point
char *tmp; // varies
int len_rep; // length of rep (the string to remove)
int len_with; // length of with (the string to replace rep with)
int len_front; // distance between rep and end of last rep
int count; // number of replacements
// sanity checks and initialization
if (!orig || !rep)
return NULL;
len_rep = strlen(rep);
if (len_rep == 0)
return NULL; // empty rep causes infinite loop during count
if (!with)
with = "";
len_with = strlen(with);
// count the number of replacements needed
ins = orig;
for (count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + len_rep;
}
tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
if (!result)
return NULL;
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
while (count--) {
ins = strstr(orig, rep);
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
}
strcpy(tmp, orig);
return result;
}
This is not provided in the standard C library because, given only a char* you can't increase the memory allocated to the string if the replacement string is longer than the string being replaced.
You can do this using std::string more easily, but even there, no single function will do it for you.
There isn't one.
You'd need to roll your own using something like strstr and strcat or strcpy.
You could build your own replace function using strstr to find the substrings and strncpy to copy in parts to a new buffer.
Unless what you want to replace_with is the same length as what you you want to replace, then it's probably best to use a new buffer to copy the new string to.
Here's some sample code that does it.
#include <string.h>
#include <stdlib.h>
char * replace(
char const * const original,
char const * const pattern,
char const * const replacement
) {
size_t const replen = strlen(replacement);
size_t const patlen = strlen(pattern);
size_t const orilen = strlen(original);
size_t patcnt = 0;
const char * oriptr;
const char * patloc;
// find how many times the pattern occurs in the original string
for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
patcnt++;
}
{
// allocate memory for the new string
size_t const retlen = orilen + patcnt * (replen - patlen);
char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) );
if (returned != NULL)
{
// copy the original string,
// replacing all the instances of the pattern
char * retptr = returned;
for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
size_t const skplen = patloc - oriptr;
// copy the section until the occurence of the pattern
strncpy(retptr, oriptr, skplen);
retptr += skplen;
// copy the replacement
strncpy(retptr, replacement, replen);
retptr += replen;
}
// copy the rest of the string.
strcpy(retptr, oriptr);
}
return returned;
}
}
#include <stdio.h>
int main(int argc, char * argv[])
{
if (argc != 4)
{
fprintf(stderr,"usage: %s <original text> <pattern> <replacement>\n", argv[0]);
exit(-1);
}
else
{
char * const newstr = replace(argv[1], argv[2], argv[3]);
if (newstr)
{
printf("%s\n", newstr);
free(newstr);
}
else
{
fprintf(stderr,"allocation error\n");
exit(-2);
}
}
return 0;
}
As strings in C can not dynamically grow inplace substitution will generally not work. Therefore you need to allocate space for a new string that has enough room for your substitution and then copy the parts from the original plus the substitution into the new string. To copy the parts you would use strncpy.
// Here is the code for unicode strings!
int mystrstr(wchar_t *txt1,wchar_t *txt2)
{
wchar_t *posstr=wcsstr(txt1,txt2);
if(posstr!=NULL)
{
return (posstr-txt1);
}else
{
return -1;
}
}
// assume: supplied buff is enough to hold generated text
void StringReplace(wchar_t *buff,wchar_t *txt1,wchar_t *txt2)
{
wchar_t *tmp;
wchar_t *nextStr;
int pos;
tmp=wcsdup(buff);
pos=mystrstr(tmp,txt1);
if(pos!=-1)
{
buff[0]=0;
wcsncpy(buff,tmp,pos);
buff[pos]=0;
wcscat(buff,txt2);
nextStr=tmp+pos+wcslen(txt1);
while(wcslen(nextStr)!=0)
{
pos=mystrstr(nextStr,txt1);
if(pos==-1)
{
wcscat(buff,nextStr);
break;
}
wcsncat(buff,nextStr,pos);
wcscat(buff,txt2);
nextStr=nextStr+pos+wcslen(txt1);
}
}
free(tmp);
}
The repl_str() function on creativeandcritical.net is fast and reliable. Also included on that page is a wide string variant, repl_wcs(), which can be used with Unicode strings including those encoded in UTF-8, through helper functions - demo code is linked from the page. Belated full disclosure: I am the author of that page and the functions on it.
Here is the one that I created based on these requirements:
Replace the pattern regardless of whether is was long or shorter.
Not use any malloc (explicit or implicit) to intrinsically avoid memory leaks.
Replace any number of occurrences of pattern.
Tolerate the replace string having a substring equal to the search string.
Does not have to check that the Line array is sufficient in size to hold the replacement. e.g. This does not work unless the caller knows that line is of sufficient size to hold the new string.
avoid use of strcat() to avoid overhead of scanning the entire string to append another string.
/* returns number of strings replaced.
*/
int replacestr(char *line, const char *search, const char *replace)
{
int count;
char *sp; // start of pattern
//printf("replacestr(%s, %s, %s)\n", line, search, replace);
if ((sp = strstr(line, search)) == NULL) {
return(0);
}
count = 1;
int sLen = strlen(search);
int rLen = strlen(replace);
if (sLen > rLen) {
// move from right to left
char *src = sp + sLen;
char *dst = sp + rLen;
while((*dst = *src) != '\0') { dst++; src++; }
} else if (sLen < rLen) {
// move from left to right
int tLen = strlen(sp) - sLen;
char *stop = sp + rLen;
char *src = sp + sLen + tLen;
char *dst = sp + rLen + tLen;
while(dst >= stop) { *dst = *src; dst--; src--; }
}
memcpy(sp, replace, rLen);
count += replacestr(sp + rLen, search, replace);
return(count);
}
Any suggestions for improving this code are cheerfully accepted. Just post the comment and I will test it.
i find most of the proposed functions hard to understand - so i came up with this:
static char *dull_replace(const char *in, const char *pattern, const char *by)
{
size_t outsize = strlen(in) + 1;
// TODO maybe avoid reallocing by counting the non-overlapping occurences of pattern
char *res = malloc(outsize);
// use this to iterate over the output
size_t resoffset = 0;
char *needle;
while (needle = strstr(in, pattern)) {
// copy everything up to the pattern
memcpy(res + resoffset, in, needle - in);
resoffset += needle - in;
// skip the pattern in the input-string
in = needle + strlen(pattern);
// adjust space for replacement
outsize = outsize - strlen(pattern) + strlen(by);
res = realloc(res, outsize);
// copy the pattern
memcpy(res + resoffset, by, strlen(by));
resoffset += strlen(by);
}
// copy the remaining input
strcpy(res + resoffset, in);
return res;
}
output must be free'd
a fix to fann95's response, using in-place modification of the string, and assuming the buffer pointed to by line is large enough to hold the resulting string.
static void replacestr(char *line, const char *search, const char *replace)
{
char *sp;
if ((sp = strstr(line, search)) == NULL) {
return;
}
int search_len = strlen(search);
int replace_len = strlen(replace);
int tail_len = strlen(sp+search_len);
memmove(sp+replace_len,sp+search_len,tail_len+1);
memcpy(sp, replace, replace_len);
}
/*замена символа в строке*/
char* replace_char(char* str, char in, char out) {
char * p = str;
while(p != '\0') {
if(*p == in)
*p == out;
++p;
}
return str;
}
This function only works if ur string has extra space for new length
void replace_str(char *str,char *org,char *rep)
{
char *ToRep = strstr(str,org);
char *Rest = (char*)malloc(strlen(ToRep));
strcpy(Rest,((ToRep)+strlen(org)));
strcpy(ToRep,rep);
strcat(ToRep,Rest);
free(Rest);
}
This only replaces First occurrence
Here goes mine, make them all char*, which makes calling easier...
char *strrpc(char *str,char *oldstr,char *newstr){
char bstr[strlen(str)];
memset(bstr,0,sizeof(bstr));
int i;
for(i = 0;i < strlen(str);i++){
if(!strncmp(str+i,oldstr,strlen(oldstr))){
strcat(bstr,newstr);
i += strlen(oldstr) - 1;
}else{
strncat(bstr,str + i,1);
}
}
strcpy(str,bstr);
return str;
}
There is a function in string.h but it works with char [] not char* but again it outputs a char* and not a char []
It is simple and beautiful
Supposing we want to replace 'and' in 'TheandQuickandBrownandFox'.
We first split with strtok and then join with snprintf defined in the stdio.h
char sometext[] = "TheandQuickandBrownandFox";
char* replaced = malloc(1024);
// split on the substring, here I am using (and)
char* token = strtok(sometext, "and");
snprintf(replaced, 1, "%s", ""); // initialise so we can compare
while(token) {
if (strcmp(replaced, "") < 1) {
// if it is the first one
snprintf(replaced, 1024, "%s", token);
token = NULL;
} else {
// put the space between the existing and new
snprintf(replaced, 1024, "%s %s", replaced, token);
token = NULL;
}
}
free(replaced);
This should give us:
The Quick Brown Fox
You can use this function (the comments explain how it works):
void strreplace(char *string, const char *find, const char *replaceWith){
if(strstr(string, find) != NULL){
char *temporaryString = malloc(strlen(strstr(string, find) + strlen(find)) + 1);
strcpy(temporaryString, strstr(string, find) + strlen(find)); //Create a string with what's after the replaced part
*strstr(string, find) = '\0'; //Take away the part to replace and the part after it in the initial string
strcat(string, replaceWith); //Concat the first part of the string with the part to replace with
strcat(string, temporaryString); //Concat the first part of the string with the part after the replaced part
free(temporaryString); //Free the memory to avoid memory leaks
}
}
DWORD ReplaceString(__inout PCHAR source, __in DWORD dwSourceLen, __in const char* pszTextToReplace, __in const char* pszReplaceWith)
{
DWORD dwRC = NO_ERROR;
PCHAR foundSeq = NULL;
PCHAR restOfString = NULL;
PCHAR searchStart = source;
size_t szReplStrcLen = strlen(pszReplaceWith), szRestOfStringLen = 0, sztextToReplaceLen = strlen(pszTextToReplace), remainingSpace = 0, dwSpaceRequired = 0;
if (strcmp(pszTextToReplace, "") == 0)
dwRC = ERROR_INVALID_PARAMETER;
else if (strcmp(pszTextToReplace, pszReplaceWith) != 0)
{
do
{
foundSeq = strstr(searchStart, pszTextToReplace);
if (foundSeq)
{
szRestOfStringLen = (strlen(foundSeq) - sztextToReplaceLen) + 1;
remainingSpace = dwSourceLen - (foundSeq - source);
dwSpaceRequired = szReplStrcLen + (szRestOfStringLen);
if (dwSpaceRequired > remainingSpace)
{
dwRC = ERROR_MORE_DATA;
}
else
{
restOfString = CMNUTIL_calloc(szRestOfStringLen, sizeof(CHAR));
strcpy_s(restOfString, szRestOfStringLen, foundSeq + sztextToReplaceLen);
strcpy_s(foundSeq, remainingSpace, pszReplaceWith);
strcat_s(foundSeq, remainingSpace, restOfString);
}
CMNUTIL_free(restOfString);
searchStart = foundSeq + szReplStrcLen; //search in the remaining str. (avoid loops when replWith contains textToRepl
}
} while (foundSeq && dwRC == NO_ERROR);
}
return dwRC;
}
char *replace(const char*instring, const char *old_part, const char *new_part)
{
#ifndef EXPECTED_REPLACEMENTS
#define EXPECTED_REPLACEMENTS 100
#endif
if(!instring || !old_part || !new_part)
{
return (char*)NULL;
}
size_t instring_len=strlen(instring);
size_t new_len=strlen(new_part);
size_t old_len=strlen(old_part);
if(instring_len<old_len || old_len==0)
{
return (char*)NULL;
}
const char *in=instring;
const char *found=NULL;
size_t count=0;
size_t out=0;
size_t ax=0;
char *outstring=NULL;
if(new_len> old_len )
{
size_t Diff=EXPECTED_REPLACEMENTS*(new_len-old_len);
size_t outstring_len=instring_len + Diff;
outstring =(char*) malloc(outstring_len);
if(!outstring){
return (char*)NULL;
}
while((found = strstr(in, old_part))!=NULL)
{
if(count==EXPECTED_REPLACEMENTS)
{
outstring_len+=Diff;
if((outstring=realloc(outstring,outstring_len))==NULL)
{
return (char*)NULL;
}
count=0;
}
ax=found-in;
strncpy(outstring+out,in,ax);
out+=ax;
strncpy(outstring+out,new_part,new_len);
out+=new_len;
in=found+old_len;
count++;
}
}
else
{
outstring =(char*) malloc(instring_len);
if(!outstring){
return (char*)NULL;
}
while((found = strstr(in, old_part))!=NULL)
{
ax=found-in;
strncpy(outstring+out,in,ax);
out+=ax;
strncpy(outstring+out,new_part,new_len);
out+=new_len;
in=found+old_len;
}
}
ax=(instring+instring_len)-in;
strncpy(outstring+out,in,ax);
out+=ax;
outstring[out]='\0';
return outstring;
}
Using only strlen from string.h
sorry for my English
char * str_replace(char * text,char * rep, char * repw){//text -> to replace in it | rep -> replace | repw -> replace with
int replen = strlen(rep),repwlen = strlen(repw),count;//some constant variables
for(int i=0;i<strlen(text);i++){//search for the first character from rep in text
if(text[i] == rep[0]){//if it found it
count = 1;//start searching from the next character to avoid repetition
for(int j=1;j<replen;j++){
if(text[i+j] == rep[j]){//see if the next character in text is the same as the next in the rep if not break
count++;
}else{
break;
}
}
if(count == replen){//if count equals to the lenght of the rep then we found the word that we want to replace in the text
if(replen < repwlen){
for(int l = strlen(text);l>i;l--){//cuz repwlen greater than replen we need to shift characters to the right to make space for the replacement to fit
text[l+repwlen-replen] = text[l];//shift by repwlen-replen
}
}
if(replen > repwlen){
for(int l=i+replen-repwlen;l<strlen(text);l++){//cuz replen greater than repwlen we need to shift the characters to the left
text[l-(replen-repwlen)] = text[l];//shift by replen-repwlen
}
text[strlen(text)-(replen-repwlen)] = '\0';//get rid of the last unwanted characters
}
for(int l=0;l<repwlen;l++){//replace rep with repwlen
text[i+l] = repw[l];
}
if(replen != repwlen){
i+=repwlen-1;//pass to the next character | try text "y" ,rep "y",repw "yy" without this line to understand
}
}
}
}
return text;
}
if you want strlen code to avoid calling string.h
int strlen(char * string){//use this code to avoid calling string.h
int lenght = 0;
while(string[lenght] != '\0'){
lenght++;
}
return lenght;
}
There you go....this is the function to replace every occurance of char x with char y within character string str
char *zStrrep(char *str, char x, char y){
char *tmp=str;
while(*tmp)
if(*tmp == x)
*tmp++ = y; /* assign first, then incement */
else
*tmp++;
// *tmp='\0'; -> we do not need this
return str;
}
An example usage could be
Exmaple Usage
char s[]="this is a trial string to test the function.";
char x=' ', y='_';
printf("%s\n",zStrrep(s,x,y));
Example Output
this_is_a_trial_string_to_test_the_function.
The function is from a string library I maintain on Github, you are more than welcome to have a look at other available functions or even contribute to the code :)
https://github.com/fnoyanisi/zString
EDIT:
#siride is right, the function above replaces chars only. Just wrote this one, which replaces character strings.
#include <stdio.h>
#include <stdlib.h>
/* replace every occurance of string x with string y */
char *zstring_replace_str(char *str, const char *x, const char *y){
char *tmp_str = str, *tmp_x = x, *dummy_ptr = tmp_x, *tmp_y = y;
int len_str=0, len_y=0, len_x=0;
/* string length */
for(; *tmp_y; ++len_y, ++tmp_y)
;
for(; *tmp_str; ++len_str, ++tmp_str)
;
for(; *tmp_x; ++len_x, ++tmp_x)
;
/* Bounds check */
if (len_y >= len_str)
return str;
/* reset tmp pointers */
tmp_y = y;
tmp_x = x;
for (tmp_str = str ; *tmp_str; ++tmp_str)
if(*tmp_str == *tmp_x) {
/* save tmp_str */
for (dummy_ptr=tmp_str; *dummy_ptr == *tmp_x; ++tmp_x, ++dummy_ptr)
if (*(tmp_x+1) == '\0' && ((dummy_ptr-str+len_y) < len_str)){
/* Reached end of x, we got something to replace then!
* Copy y only if there is enough room for it
*/
for(tmp_y=y; *tmp_y; ++tmp_y, ++tmp_str)
*tmp_str = *tmp_y;
}
/* reset tmp_x */
tmp_x = x;
}
return str;
}
int main()
{
char s[]="Free software is a matter of liberty, not price.\n"
"To understand the concept, you should think of 'free' \n"
"as in 'free speech', not as in 'free beer'";
printf("%s\n\n",s);
printf("%s\n",zstring_replace_str(s,"ree","XYZ"));
return 0;
}
And below is the output
Free software is a matter of liberty, not price.
To understand the concept, you should think of 'free'
as in 'free speech', not as in 'free beer'
FXYZ software is a matter of liberty, not price.
To understand the concept, you should think of 'fXYZ'
as in 'fXYZ speech', not as in 'fXYZ beer'
You can use strrep()
char* strrep ( const char * cadena,
const char * strf,
const char * strr
)
strrep (String Replace). Replaces strf with strr in cadena and returns the new string. You need to free the returned string in your code after using strrep.
Parameters:
cadena: The string with the text.
strf: The text to find.
strr: The replacement text.
Returns
The text updated wit the replacement.
Project can be found at https://github.com/ipserc/strrep
Given a (char *) string, I want to find all occurrences of a substring and replace them with an alternate string. I do not see any simple function that achieves this in <string.h>.
The optimizer should eliminate most of the local variables. The tmp pointer is there to make sure strcpy doesn't have to walk the string to find the null. tmp points to the end of result after each call. (See Shlemiel the painter's algorithm for why strcpy can be annoying.)
// You must free the result if result is non-NULL.
char *str_replace(char *orig, char *rep, char *with) {
char *result; // the return string
char *ins; // the next insert point
char *tmp; // varies
int len_rep; // length of rep (the string to remove)
int len_with; // length of with (the string to replace rep with)
int len_front; // distance between rep and end of last rep
int count; // number of replacements
// sanity checks and initialization
if (!orig || !rep)
return NULL;
len_rep = strlen(rep);
if (len_rep == 0)
return NULL; // empty rep causes infinite loop during count
if (!with)
with = "";
len_with = strlen(with);
// count the number of replacements needed
ins = orig;
for (count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + len_rep;
}
tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
if (!result)
return NULL;
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
while (count--) {
ins = strstr(orig, rep);
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
}
strcpy(tmp, orig);
return result;
}
This is not provided in the standard C library because, given only a char* you can't increase the memory allocated to the string if the replacement string is longer than the string being replaced.
You can do this using std::string more easily, but even there, no single function will do it for you.
There isn't one.
You'd need to roll your own using something like strstr and strcat or strcpy.
You could build your own replace function using strstr to find the substrings and strncpy to copy in parts to a new buffer.
Unless what you want to replace_with is the same length as what you you want to replace, then it's probably best to use a new buffer to copy the new string to.
Here's some sample code that does it.
#include <string.h>
#include <stdlib.h>
char * replace(
char const * const original,
char const * const pattern,
char const * const replacement
) {
size_t const replen = strlen(replacement);
size_t const patlen = strlen(pattern);
size_t const orilen = strlen(original);
size_t patcnt = 0;
const char * oriptr;
const char * patloc;
// find how many times the pattern occurs in the original string
for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
patcnt++;
}
{
// allocate memory for the new string
size_t const retlen = orilen + patcnt * (replen - patlen);
char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) );
if (returned != NULL)
{
// copy the original string,
// replacing all the instances of the pattern
char * retptr = returned;
for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
size_t const skplen = patloc - oriptr;
// copy the section until the occurence of the pattern
strncpy(retptr, oriptr, skplen);
retptr += skplen;
// copy the replacement
strncpy(retptr, replacement, replen);
retptr += replen;
}
// copy the rest of the string.
strcpy(retptr, oriptr);
}
return returned;
}
}
#include <stdio.h>
int main(int argc, char * argv[])
{
if (argc != 4)
{
fprintf(stderr,"usage: %s <original text> <pattern> <replacement>\n", argv[0]);
exit(-1);
}
else
{
char * const newstr = replace(argv[1], argv[2], argv[3]);
if (newstr)
{
printf("%s\n", newstr);
free(newstr);
}
else
{
fprintf(stderr,"allocation error\n");
exit(-2);
}
}
return 0;
}
As strings in C can not dynamically grow inplace substitution will generally not work. Therefore you need to allocate space for a new string that has enough room for your substitution and then copy the parts from the original plus the substitution into the new string. To copy the parts you would use strncpy.
// Here is the code for unicode strings!
int mystrstr(wchar_t *txt1,wchar_t *txt2)
{
wchar_t *posstr=wcsstr(txt1,txt2);
if(posstr!=NULL)
{
return (posstr-txt1);
}else
{
return -1;
}
}
// assume: supplied buff is enough to hold generated text
void StringReplace(wchar_t *buff,wchar_t *txt1,wchar_t *txt2)
{
wchar_t *tmp;
wchar_t *nextStr;
int pos;
tmp=wcsdup(buff);
pos=mystrstr(tmp,txt1);
if(pos!=-1)
{
buff[0]=0;
wcsncpy(buff,tmp,pos);
buff[pos]=0;
wcscat(buff,txt2);
nextStr=tmp+pos+wcslen(txt1);
while(wcslen(nextStr)!=0)
{
pos=mystrstr(nextStr,txt1);
if(pos==-1)
{
wcscat(buff,nextStr);
break;
}
wcsncat(buff,nextStr,pos);
wcscat(buff,txt2);
nextStr=nextStr+pos+wcslen(txt1);
}
}
free(tmp);
}
The repl_str() function on creativeandcritical.net is fast and reliable. Also included on that page is a wide string variant, repl_wcs(), which can be used with Unicode strings including those encoded in UTF-8, through helper functions - demo code is linked from the page. Belated full disclosure: I am the author of that page and the functions on it.
Here is the one that I created based on these requirements:
Replace the pattern regardless of whether is was long or shorter.
Not use any malloc (explicit or implicit) to intrinsically avoid memory leaks.
Replace any number of occurrences of pattern.
Tolerate the replace string having a substring equal to the search string.
Does not have to check that the Line array is sufficient in size to hold the replacement. e.g. This does not work unless the caller knows that line is of sufficient size to hold the new string.
avoid use of strcat() to avoid overhead of scanning the entire string to append another string.
/* returns number of strings replaced.
*/
int replacestr(char *line, const char *search, const char *replace)
{
int count;
char *sp; // start of pattern
//printf("replacestr(%s, %s, %s)\n", line, search, replace);
if ((sp = strstr(line, search)) == NULL) {
return(0);
}
count = 1;
int sLen = strlen(search);
int rLen = strlen(replace);
if (sLen > rLen) {
// move from right to left
char *src = sp + sLen;
char *dst = sp + rLen;
while((*dst = *src) != '\0') { dst++; src++; }
} else if (sLen < rLen) {
// move from left to right
int tLen = strlen(sp) - sLen;
char *stop = sp + rLen;
char *src = sp + sLen + tLen;
char *dst = sp + rLen + tLen;
while(dst >= stop) { *dst = *src; dst--; src--; }
}
memcpy(sp, replace, rLen);
count += replacestr(sp + rLen, search, replace);
return(count);
}
Any suggestions for improving this code are cheerfully accepted. Just post the comment and I will test it.
i find most of the proposed functions hard to understand - so i came up with this:
static char *dull_replace(const char *in, const char *pattern, const char *by)
{
size_t outsize = strlen(in) + 1;
// TODO maybe avoid reallocing by counting the non-overlapping occurences of pattern
char *res = malloc(outsize);
// use this to iterate over the output
size_t resoffset = 0;
char *needle;
while (needle = strstr(in, pattern)) {
// copy everything up to the pattern
memcpy(res + resoffset, in, needle - in);
resoffset += needle - in;
// skip the pattern in the input-string
in = needle + strlen(pattern);
// adjust space for replacement
outsize = outsize - strlen(pattern) + strlen(by);
res = realloc(res, outsize);
// copy the pattern
memcpy(res + resoffset, by, strlen(by));
resoffset += strlen(by);
}
// copy the remaining input
strcpy(res + resoffset, in);
return res;
}
output must be free'd
a fix to fann95's response, using in-place modification of the string, and assuming the buffer pointed to by line is large enough to hold the resulting string.
static void replacestr(char *line, const char *search, const char *replace)
{
char *sp;
if ((sp = strstr(line, search)) == NULL) {
return;
}
int search_len = strlen(search);
int replace_len = strlen(replace);
int tail_len = strlen(sp+search_len);
memmove(sp+replace_len,sp+search_len,tail_len+1);
memcpy(sp, replace, replace_len);
}
/*замена символа в строке*/
char* replace_char(char* str, char in, char out) {
char * p = str;
while(p != '\0') {
if(*p == in)
*p == out;
++p;
}
return str;
}
This function only works if ur string has extra space for new length
void replace_str(char *str,char *org,char *rep)
{
char *ToRep = strstr(str,org);
char *Rest = (char*)malloc(strlen(ToRep));
strcpy(Rest,((ToRep)+strlen(org)));
strcpy(ToRep,rep);
strcat(ToRep,Rest);
free(Rest);
}
This only replaces First occurrence
Here goes mine, make them all char*, which makes calling easier...
char *strrpc(char *str,char *oldstr,char *newstr){
char bstr[strlen(str)];
memset(bstr,0,sizeof(bstr));
int i;
for(i = 0;i < strlen(str);i++){
if(!strncmp(str+i,oldstr,strlen(oldstr))){
strcat(bstr,newstr);
i += strlen(oldstr) - 1;
}else{
strncat(bstr,str + i,1);
}
}
strcpy(str,bstr);
return str;
}
There is a function in string.h but it works with char [] not char* but again it outputs a char* and not a char []
It is simple and beautiful
Supposing we want to replace 'and' in 'TheandQuickandBrownandFox'.
We first split with strtok and then join with snprintf defined in the stdio.h
char sometext[] = "TheandQuickandBrownandFox";
char* replaced = malloc(1024);
// split on the substring, here I am using (and)
char* token = strtok(sometext, "and");
snprintf(replaced, 1, "%s", ""); // initialise so we can compare
while(token) {
if (strcmp(replaced, "") < 1) {
// if it is the first one
snprintf(replaced, 1024, "%s", token);
token = NULL;
} else {
// put the space between the existing and new
snprintf(replaced, 1024, "%s %s", replaced, token);
token = NULL;
}
}
free(replaced);
This should give us:
The Quick Brown Fox
You can use this function (the comments explain how it works):
void strreplace(char *string, const char *find, const char *replaceWith){
if(strstr(string, find) != NULL){
char *temporaryString = malloc(strlen(strstr(string, find) + strlen(find)) + 1);
strcpy(temporaryString, strstr(string, find) + strlen(find)); //Create a string with what's after the replaced part
*strstr(string, find) = '\0'; //Take away the part to replace and the part after it in the initial string
strcat(string, replaceWith); //Concat the first part of the string with the part to replace with
strcat(string, temporaryString); //Concat the first part of the string with the part after the replaced part
free(temporaryString); //Free the memory to avoid memory leaks
}
}
DWORD ReplaceString(__inout PCHAR source, __in DWORD dwSourceLen, __in const char* pszTextToReplace, __in const char* pszReplaceWith)
{
DWORD dwRC = NO_ERROR;
PCHAR foundSeq = NULL;
PCHAR restOfString = NULL;
PCHAR searchStart = source;
size_t szReplStrcLen = strlen(pszReplaceWith), szRestOfStringLen = 0, sztextToReplaceLen = strlen(pszTextToReplace), remainingSpace = 0, dwSpaceRequired = 0;
if (strcmp(pszTextToReplace, "") == 0)
dwRC = ERROR_INVALID_PARAMETER;
else if (strcmp(pszTextToReplace, pszReplaceWith) != 0)
{
do
{
foundSeq = strstr(searchStart, pszTextToReplace);
if (foundSeq)
{
szRestOfStringLen = (strlen(foundSeq) - sztextToReplaceLen) + 1;
remainingSpace = dwSourceLen - (foundSeq - source);
dwSpaceRequired = szReplStrcLen + (szRestOfStringLen);
if (dwSpaceRequired > remainingSpace)
{
dwRC = ERROR_MORE_DATA;
}
else
{
restOfString = CMNUTIL_calloc(szRestOfStringLen, sizeof(CHAR));
strcpy_s(restOfString, szRestOfStringLen, foundSeq + sztextToReplaceLen);
strcpy_s(foundSeq, remainingSpace, pszReplaceWith);
strcat_s(foundSeq, remainingSpace, restOfString);
}
CMNUTIL_free(restOfString);
searchStart = foundSeq + szReplStrcLen; //search in the remaining str. (avoid loops when replWith contains textToRepl
}
} while (foundSeq && dwRC == NO_ERROR);
}
return dwRC;
}
char *replace(const char*instring, const char *old_part, const char *new_part)
{
#ifndef EXPECTED_REPLACEMENTS
#define EXPECTED_REPLACEMENTS 100
#endif
if(!instring || !old_part || !new_part)
{
return (char*)NULL;
}
size_t instring_len=strlen(instring);
size_t new_len=strlen(new_part);
size_t old_len=strlen(old_part);
if(instring_len<old_len || old_len==0)
{
return (char*)NULL;
}
const char *in=instring;
const char *found=NULL;
size_t count=0;
size_t out=0;
size_t ax=0;
char *outstring=NULL;
if(new_len> old_len )
{
size_t Diff=EXPECTED_REPLACEMENTS*(new_len-old_len);
size_t outstring_len=instring_len + Diff;
outstring =(char*) malloc(outstring_len);
if(!outstring){
return (char*)NULL;
}
while((found = strstr(in, old_part))!=NULL)
{
if(count==EXPECTED_REPLACEMENTS)
{
outstring_len+=Diff;
if((outstring=realloc(outstring,outstring_len))==NULL)
{
return (char*)NULL;
}
count=0;
}
ax=found-in;
strncpy(outstring+out,in,ax);
out+=ax;
strncpy(outstring+out,new_part,new_len);
out+=new_len;
in=found+old_len;
count++;
}
}
else
{
outstring =(char*) malloc(instring_len);
if(!outstring){
return (char*)NULL;
}
while((found = strstr(in, old_part))!=NULL)
{
ax=found-in;
strncpy(outstring+out,in,ax);
out+=ax;
strncpy(outstring+out,new_part,new_len);
out+=new_len;
in=found+old_len;
}
}
ax=(instring+instring_len)-in;
strncpy(outstring+out,in,ax);
out+=ax;
outstring[out]='\0';
return outstring;
}
Using only strlen from string.h
sorry for my English
char * str_replace(char * text,char * rep, char * repw){//text -> to replace in it | rep -> replace | repw -> replace with
int replen = strlen(rep),repwlen = strlen(repw),count;//some constant variables
for(int i=0;i<strlen(text);i++){//search for the first character from rep in text
if(text[i] == rep[0]){//if it found it
count = 1;//start searching from the next character to avoid repetition
for(int j=1;j<replen;j++){
if(text[i+j] == rep[j]){//see if the next character in text is the same as the next in the rep if not break
count++;
}else{
break;
}
}
if(count == replen){//if count equals to the lenght of the rep then we found the word that we want to replace in the text
if(replen < repwlen){
for(int l = strlen(text);l>i;l--){//cuz repwlen greater than replen we need to shift characters to the right to make space for the replacement to fit
text[l+repwlen-replen] = text[l];//shift by repwlen-replen
}
}
if(replen > repwlen){
for(int l=i+replen-repwlen;l<strlen(text);l++){//cuz replen greater than repwlen we need to shift the characters to the left
text[l-(replen-repwlen)] = text[l];//shift by replen-repwlen
}
text[strlen(text)-(replen-repwlen)] = '\0';//get rid of the last unwanted characters
}
for(int l=0;l<repwlen;l++){//replace rep with repwlen
text[i+l] = repw[l];
}
if(replen != repwlen){
i+=repwlen-1;//pass to the next character | try text "y" ,rep "y",repw "yy" without this line to understand
}
}
}
}
return text;
}
if you want strlen code to avoid calling string.h
int strlen(char * string){//use this code to avoid calling string.h
int lenght = 0;
while(string[lenght] != '\0'){
lenght++;
}
return lenght;
}
There you go....this is the function to replace every occurance of char x with char y within character string str
char *zStrrep(char *str, char x, char y){
char *tmp=str;
while(*tmp)
if(*tmp == x)
*tmp++ = y; /* assign first, then incement */
else
*tmp++;
// *tmp='\0'; -> we do not need this
return str;
}
An example usage could be
Exmaple Usage
char s[]="this is a trial string to test the function.";
char x=' ', y='_';
printf("%s\n",zStrrep(s,x,y));
Example Output
this_is_a_trial_string_to_test_the_function.
The function is from a string library I maintain on Github, you are more than welcome to have a look at other available functions or even contribute to the code :)
https://github.com/fnoyanisi/zString
EDIT:
#siride is right, the function above replaces chars only. Just wrote this one, which replaces character strings.
#include <stdio.h>
#include <stdlib.h>
/* replace every occurance of string x with string y */
char *zstring_replace_str(char *str, const char *x, const char *y){
char *tmp_str = str, *tmp_x = x, *dummy_ptr = tmp_x, *tmp_y = y;
int len_str=0, len_y=0, len_x=0;
/* string length */
for(; *tmp_y; ++len_y, ++tmp_y)
;
for(; *tmp_str; ++len_str, ++tmp_str)
;
for(; *tmp_x; ++len_x, ++tmp_x)
;
/* Bounds check */
if (len_y >= len_str)
return str;
/* reset tmp pointers */
tmp_y = y;
tmp_x = x;
for (tmp_str = str ; *tmp_str; ++tmp_str)
if(*tmp_str == *tmp_x) {
/* save tmp_str */
for (dummy_ptr=tmp_str; *dummy_ptr == *tmp_x; ++tmp_x, ++dummy_ptr)
if (*(tmp_x+1) == '\0' && ((dummy_ptr-str+len_y) < len_str)){
/* Reached end of x, we got something to replace then!
* Copy y only if there is enough room for it
*/
for(tmp_y=y; *tmp_y; ++tmp_y, ++tmp_str)
*tmp_str = *tmp_y;
}
/* reset tmp_x */
tmp_x = x;
}
return str;
}
int main()
{
char s[]="Free software is a matter of liberty, not price.\n"
"To understand the concept, you should think of 'free' \n"
"as in 'free speech', not as in 'free beer'";
printf("%s\n\n",s);
printf("%s\n",zstring_replace_str(s,"ree","XYZ"));
return 0;
}
And below is the output
Free software is a matter of liberty, not price.
To understand the concept, you should think of 'free'
as in 'free speech', not as in 'free beer'
FXYZ software is a matter of liberty, not price.
To understand the concept, you should think of 'fXYZ'
as in 'fXYZ speech', not as in 'fXYZ beer'
You can use strrep()
char* strrep ( const char * cadena,
const char * strf,
const char * strr
)
strrep (String Replace). Replaces strf with strr in cadena and returns the new string. You need to free the returned string in your code after using strrep.
Parameters:
cadena: The string with the text.
strf: The text to find.
strr: The replacement text.
Returns
The text updated wit the replacement.
Project can be found at https://github.com/ipserc/strrep