在 C 语言中,从字符串中替换子字符串的函数是什么?

给定一个(char *)字符串,我希望找到子字符串的所有匹配项,并将它们替换为备用字符串。我没有看到任何简单的函数能够在 <string.h>中实现这一点。

344383 次浏览

You could build your own replace function using strstr to find the substrings and strncpy to copy in parts to a new buffer.

除非您想要的 replace_with的长度与您想要的 replace的长度相同,否则最好使用一个新的缓冲区将新字符串复制到。

根本没有。

您需要使用类似于 strstr和 strcat 或 strcpy 的东西来滚动您自己的。

标准 C 库中没有提供这一点,因为只给定一个 char * ,如果替换的字符串比被替换的字符串长,就不能增加分配给字符串的内存。

您可以使用 std: : string 更容易地完成这项工作,但是即使在那里,也没有一个函数可以为您完成这项工作。

由于 C 中的字符串不能动态增长,因此替换通常不会起作用。因此,您需要为一个有足够空间进行替换的新字符串分配空间,然后将原始字符串中的部分加上替换复制到新字符串中。要复制零件,可以使用 严格

优化器应该消除大部分局部变量。Tmp 指针用于确保 strcpy 不必遍历字符串来查找 null。Tmp 指向每次调用后的结果结束。(请参阅 画家 Shlemiel 的算法了解 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;
}

下面是一些示例代码。

#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);
}

Creativeandcritical.net 上的 Repl _ str ()功能快速可靠。该页面还包括一个宽字符串变体 repl_wcs(),它可以通过 helper 函数与 Unicode 字符串(包括那些用 UTF-8编码的字符串)一起使用——演示代码从页面链接。迟来的全面披露: 我是该页面的作者及其上的功能。

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;
}

我发现大多数提议的函数都很难理解——所以我想出了这个办法:

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

下面是我根据这些要求创建的一个:

  1. 不管模式是长的还是短的,都要替换它。

  2. Not use any malloc (explicit or implicit) to intrinsically avoid memory leaks.

  3. 替换任意数量的模式出现。

  4. 允许替换字符串的子字符串等于搜索字符串。

  5. 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.

  6. 避免使用 strcat ()来避免扫描整个字符串以附加另一个字符串的开销。

/* 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);
}

任何改进此代码的建议都会被愉快地接受。只要发表评论,我将对其进行测试。

修复 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);
}

就是这样... ... 这个函数用字符串 str中的 char y替换每次出现的 char x

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;
}

示例用法可以是

  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 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;
}

下面是输出

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'

您可以使用这个函数(注释解释了它的工作原理) :

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
}
}
/*замена символа в строке*/
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;
}

这个函数只有在你的字符串有额外的空间来存放新的长度时才有效

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);
}
}
}

这是我的,把它们都做成 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;
}

仅使用 strlen from 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;
}

你可以使用 strrep()

char* strrep    (   const char *    cadena,
const char *    strf,
const char *    strr
)

字符串替换。在 cadena中用 strr替换 strf并返回新字符串。在使用 strep 之后,需要释放代码中返回的字符串。

参数:

  • cadena: 包含文本的字符串。
  • 要查找的文本。
  • strr: 替换文本。

报税表 文本随替换更新。

项目可以在 https://github.com/ipserc/strrep找到

string.h中有一个函数,但是它与 char []一起工作,而不是与 char*一起工作,但是它再次输出一个 char*而不是一个 char []

它简单而美丽

假设我们想要替换“ TheandQuickandBrownandFox”中的“ and”。

我们首先使用 strtok进行分割,然后使用 stdio.h中定义的 snprintf进行连接

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);

这应该会给我们:

快速棕狐