Учитывая char *строку ( ), я хочу найти все вхождения подстроки и заменить их альтернативной строкой. Я не вижу простой функции, позволяющей добиться этого в <string.h>.
Я сомневаюсь, что вы можете сделать это изменчивым способом
user44511
Ответы:
90
Оптимизатор должен исключить большинство локальных переменных. Указатель tmp нужен, чтобы убедиться, что strcpy не нужно обходить строку, чтобы найти нуль. tmp указывает на конец результата после каждого вызова. (См. Алгоритм художника Шлемиэля, чтобы узнать, почему strcpy может раздражать.)
// You must free the result if result is non-NULL.char *str_replace(char *orig, char *rep, char *with){
char *result; // the return stringchar *ins; // the next insert pointchar *tmp; // variesint 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 repint count; // number of replacements// sanity checks and initializationif (!orig || !rep)
returnNULL;
len_rep = strlen(rep);
if (len_rep == 0)
returnNULL; // empty rep causes infinite loop during countif (!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)
returnNULL;
// 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;
}
@jmucchiello: использовать size_tвместо intпроизвольных размеров объектов / строк и индексов в них. Кроме того, какова цель strcpy(tmp, orig);в самом конце? Это кажется неправильным.
Алексей Фрунзе
@Alex, последний strcpy (tmp, orig) копирует последнюю часть строки в место назначения. Например: replace («abab», «a», «c») в конце цикла, результат содержит «cbc», а orig указывает на последний «b» в «abab». Последний strcpy добавляет «b», поэтому возвращаемая строка - «cbcb». Если скопировать нечего, то orig должен указывать на ASCIIZ входной строки.
jmucchiello
упрощение: вы можете заменить этот первый forцикл на for (count = 1; ins = strstr(ins + rep_len, rep); ++count) {}, затем tmpон используется только для записи.
Имейте в виду, что эта функция возвращает NULL, если нет экземпляров для замены (if (! (Ins = strstr (orig, rep))) return NULL;). Вы не можете просто использовать вывод, вам нужно проверить, является ли вывод NULL, и если да, используйте исходную строку (не просто копируйте указатель на строку результата, потому что free (result) затем освобождает исходную строку). Использование становится более простым, если входная строка просто копируется в выходную строку, если заменять нечего.
Adversus
18
Это не предусмотрено в стандартной библиотеке C, потому что, учитывая только символ *, вы не можете увеличить память, выделенную для строки, если строка для замены длиннее заменяемой строки.
Вы можете сделать это проще, используя std :: string, но даже там ни одна функция не сделает это за вас.
1 / strlen (char *) + 1 не обязательно равен размеру хранилища. 2 / Существует много N версий строковых функций, которые получают дополнительный параметр размера буфера, поэтому нет причин, по которым не могло быть snreplace (). 3 / может быть функция замены на месте, а не функция замены на месте. 4 / как вы думаете, работает sprintf? Ему задан аргумент char *, и ему не нужно увеличивать выделение памяти, поэтому нет причин, по которым замена тоже не может работать ... (хотя C имеет плохой "строковый" дизайн, и размер буфера всегда следует передавать с указателем => snprintf)
Стивен Спарк
12
Нет ни одного.
Вам нужно будет свернуть свой собственный, используя что-то вроде strstr и strcat или strcpy.
Где хранятся фанатские коллекции часто используемых функций? Наверняка для этого уже есть библиотека ....
Пэйсьер
1
strcat()плохое предложение.
Ихароб Аль-Асими,
11
Вы можете создать свою собственную функцию замены, используя strstr для поиска подстрок и strncpy для копирования по частям в новый буфер.
Если то, что вы хотите, replace_withимеет ту же длину, что и то, что вы хотите replace, тогда, вероятно, лучше всего использовать новый буфер для копирования новой строки.
Поскольку строки в C не могут динамически расти на месте, подстановка обычно не работает. Следовательно, вам необходимо выделить место для новой строки, в которой достаточно места для вашей замены, а затем скопировать части из оригинала плюс подстановка в новую строку. Чтобы скопировать части, вы должны использовать strncpy .
Размер буфера может быть больше strlen, строка замены может быть меньше заменяемой строки ... поэтому вам не нужно выделять память для выполнения замены. (Также на микроконтроллерах у вас может не быть бесконечной памяти, и вам может потребоваться выполнить замену на месте. Копирование всего в новый буфер может быть не лучшим решением для всех ...)
Стивен Спарк,
8
Вот пример кода, который это делает.
#include<string.h>#include<stdlib.h>char * replace(
charconst * const original,
charconst * const pattern,
charconst * const replacement
){
size_tconst replen = strlen(replacement);
size_tconst patlen = strlen(pattern);
size_tconst orilen = strlen(original);
size_t patcnt = 0;
constchar * oriptr;
constchar * patloc;
// find how many times the pattern occurs in the original stringfor (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
patcnt++;
}
{
// allocate memory for the new stringsize_tconst 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 patternchar * retptr = returned;
for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
size_tconst skplen = patloc - oriptr;
// copy the section until the occurence of the patternstrncpy(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>intmain(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);
}
}
return0;
}
Функция repl_str () на сайте creativeandcritical.net работает быстро и надежно. На эту страницу также включен вариант с широкой строкой, repl_wcs () , который можно использовать со строками Unicode, включая те, которые закодированы в UTF-8, через вспомогательные функции - демонстрационный код связан со страницей. Запоздалое полное раскрытие информации: я являюсь автором этой страницы и функций на ней.
Не понимаю, как это могло быть. Есть только один malloc, и вызывающий получает указание освободить память, когда она больше не требуется. Не могли бы Вы уточнить?
Laird
@Lairdpos_cache = realloc(pos_cache
PSkocik 03
@PSkocik Функция была обновлена после жалобы @MightyPork, но даже несмотря на то, что теперь она имеет дополнительный malloc / realloc для pos_cache, я не вижу пути кода, который позволяет избежать free(pos_cache);конца функции at.
Laird
@Laird reallocможет потерпеть неудачу. Если это так, он возвращается NULLи оставляет старый указатель нетронутым. p = realloc(p, x)в случае неудачи перезапишет действительный указатель кучи pс помощью NULL, и если это pбыла ваша единственная ссылка на этот объект кучи, вы теперь его утекли. Это классическая ошибка новичков.
PSkocik
3
Мне трудно понять большинство предлагаемых функций, поэтому я придумал следующее:
staticchar *dull_replace(constchar *in, constchar *pattern, constchar *by){
size_t outsize = strlen(in) + 1;
// TODO maybe avoid reallocing by counting the non-overlapping occurences of patternchar *res = malloc(outsize);
// use this to iterate over the outputsize_t resoffset = 0;
char *needle;
while (needle = strstr(in, pattern)) {
// copy everything up to the patternmemcpy(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 patternmemcpy(res + resoffset, by, strlen(by));
resoffset += strlen(by);
}
// copy the remaining inputstrcpy(res + resoffset, in);
return res;
}
Вы можете использовать эту функцию (комментарии объясняют, как она работает):
voidstrreplace(char *string, constchar *find, constchar *replaceWith){
if(strstr(string, replaceWith) != 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 stringstrcat(string, replaceWith); //Concat the first part of the string with the part to replace withstrcat(string, temporaryString); //Concat the first part of the string with the part after the replaced partfree(temporaryString); //Free the memory to avoid memory leaks
}
}
Вот тот, который я создал исходя из этих требований:
Замените узор независимо от того, был он длинным или короче.
Не используйте malloc (явный или неявный), чтобы избежать утечек памяти.
Заменить любое количество вхождений шаблона.
Допускать замену строки с подстрокой, равной строке поиска.
Нет необходимости проверять, что линейный массив достаточен по размеру для проведения замены. Например, это не сработает, если вызывающий абонент не знает, что размер строки достаточен для хранения новой строки.
strrep (замена строки). Заменяет strf на strr в cadena и возвращает новую строку. После использования strrep вам необходимо освободить возвращаемую строку в коде.
Параметры cadena Строка с текстом. strf Текст, который нужно найти. strr Текст замены.
исправление ответа fann95, использующее модификацию строки на месте и предполагающее, что буфер, на который указывает строка, достаточно велик для хранения результирующей строки.
staticvoidreplacestr(char *line, constchar *search, constchar *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);
}
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.
РЕДАКТИРОВАТЬ: @siride прав, функция выше заменяет только символы. Только что написал вот этот, который заменяет символьные строки.
#include<stdio.h>#include<stdlib.h>/* replace every occurance of string x with string y */char *zstring_replace_str(char *str, constchar *x, constchar *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;
}
intmain(){
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"));
return0;
}
И ниже вывод
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'
char * str_replace(char * text,char * rep, char * repw){//text -> to replace in it | rep -> replace | repw -> replace withint replen = strlen(rep),repwlen = strlen(repw),count;//some constant variablesfor(int i=0;i<strlen(text);i++){//search for the first character from rep in textif(text[i] == rep[0]){//if it found it
count = 1;//start searching from the next character to avoid repetitionfor(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 textif(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;
}
если вы хотите, чтобы код strlen избегал вызова string.h
intstrlen(char * string){//use this code to avoid calling string.hint lenght = 0;
while(string[lenght] != '\0'){
lenght++;
}
return lenght;
}
Ответы:
Оптимизатор должен исключить большинство локальных переменных. Указатель tmp нужен, чтобы убедиться, что strcpy не нужно обходить строку, чтобы найти нуль. tmp указывает на конец результата после каждого вызова. (См. Алгоритм художника Шлемиэля, чтобы узнать, почему strcpy может раздражать.)
// 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; }
источник
size_t
вместоint
произвольных размеров объектов / строк и индексов в них. Кроме того, какова цельstrcpy(tmp, orig);
в самом конце? Это кажется неправильным.for
цикл наfor (count = 1; ins = strstr(ins + rep_len, rep); ++count) {}
, затемtmp
он используется только для записи.Это не предусмотрено в стандартной библиотеке C, потому что, учитывая только символ *, вы не можете увеличить память, выделенную для строки, если строка для замены длиннее заменяемой строки.
Вы можете сделать это проще, используя std :: string, но даже там ни одна функция не сделает это за вас.
источник
Нет ни одного.
Вам нужно будет свернуть свой собственный, используя что-то вроде strstr и strcat или strcpy.
источник
strcat()
плохое предложение.Вы можете создать свою собственную функцию замены, используя strstr для поиска подстрок и strncpy для копирования по частям в новый буфер.
Если то, что вы хотите,
replace_with
имеет ту же длину, что и то, что вы хотитеreplace
, тогда, вероятно, лучше всего использовать новый буфер для копирования новой строки.источник
Поскольку строки в C не могут динамически расти на месте, подстановка обычно не работает. Следовательно, вам необходимо выделить место для новой строки, в которой достаточно места для вашей замены, а затем скопировать части из оригинала плюс подстановка в новую строку. Чтобы скопировать части, вы должны использовать strncpy .
источник
Вот пример кода, который это делает.
#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; }
источник
// 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); }
источник
Функция repl_str () на сайте creativeandcritical.net работает быстро и надежно. На эту страницу также включен вариант с широкой строкой, repl_wcs () , который можно использовать со строками Unicode, включая те, которые закодированы в UTF-8, через вспомогательные функции - демонстрационный код связан со страницей. Запоздалое полное раскрытие информации: я являюсь автором этой страницы и функций на ней.
источник
pos_cache = realloc(pos_cache
free(pos_cache);
конца функции at.realloc
может потерпеть неудачу. Если это так, он возвращаетсяNULL
и оставляет старый указатель нетронутым.p = realloc(p, x)
в случае неудачи перезапишет действительный указатель кучиp
с помощьюNULL
, и если этоp
была ваша единственная ссылка на этот объект кучи, вы теперь его утекли. Это классическая ошибка новичков.Мне трудно понять большинство предлагаемых функций, поэтому я придумал следующее:
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; }
вывод должен быть свободен
источник
Вы можете использовать эту функцию (комментарии объясняют, как она работает):
void strreplace(char *string, const char *find, const char *replaceWith){ if(strstr(string, replaceWith) != 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 } }
источник
Вот тот, который я создал исходя из этих требований:
Замените узор независимо от того, был он длинным или короче.
Не используйте malloc (явный или неявный), чтобы избежать утечек памяти.
Заменить любое количество вхождений шаблона.
Допускать замену строки с подстрокой, равной строке поиска.
Нет необходимости проверять, что линейный массив достаточен по размеру для проведения замены. Например, это не сработает, если вызывающий абонент не знает, что размер строки достаточен для хранения новой строки.
/* 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); }
Мы с радостью принимаем любые предложения по улучшению этого кода. Просто оставьте комментарий, и я его протестирую.
источник
Вот и мой, сделайте их всех char *, чтобы было проще звонить ...
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; }
источник
Вы можете использовать strrep ()
char * strrep (const char * cadena, const char * strf, const char * strr)
strrep (замена строки). Заменяет strf на strr в cadena и возвращает новую строку. После использования strrep вам необходимо освободить возвращаемую строку в коде.
Параметры cadena Строка с текстом. strf Текст, который нужно найти. strr Текст замены.
Возвращает Текст обновлен с заменой.
Проект можно найти на https://github.com/ipserc/strrep
источник
исправление ответа fann95, использующее модификацию строки на месте и предполагающее, что буфер, на который указывает строка, достаточно велик для хранения результирующей строки.
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 x
вchar y
пределах строки символов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'; return str; }
Пример использования может быть
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.
Функция взята из строковой библиотеки, которую я поддерживаю на Github , вы можете ознакомиться с другими доступными функциями или даже внести свой вклад в код :)
https://github.com/fnoyanisi/zString
РЕДАКТИРОВАТЬ: @siride прав, функция выше заменяет только символы. Только что написал вот этот, который заменяет символьные строки.
#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; }
И ниже вывод
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'
источник
/*замена символа в строке*/ char* replace_char(char* str, char in, char out) { char * p = str; while(p != '\0') { if(*p == in) *p == out; ++p; } return str; }
источник
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; }
источник
Эта функция работает, только если в строке ur есть дополнительное пространство для новой длины
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); }
Это заменяет только первое вхождение
источник
Вот мой, он самодостаточный и универсальный, а также эффективный, он увеличивает или сжимает буферы по мере необходимости в каждой рекурсии.
void strreplace(char *src, char *str, char *rep) { char *p = strstr(src, str); if (p) { int len = strlen(src)+strlen(rep)-strlen(str); char r[len]; memset(r, 0, len); if ( p >= src ){ strncpy(r, src, p-src); r[p-src]='\0'; strncat(r, rep, strlen(rep)); strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); strcpy(src, r); strreplace(p+strlen(rep), str, rep); } } }
источник
Использование только strlen из string.h
Извините за мой английский
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; }
если вы хотите, чтобы код strlen избегал вызова string.h
int strlen(char * string){//use this code to avoid calling string.h int lenght = 0; while(string[lenght] != '\0'){ lenght++; } return lenght; }
источник