c字符串中的多个替换字符串

时间:2009-09-29 21:30:55

标签: c string

假设我有一个字符串:

"(aaa and bbb or (aaa or aaa or bbb))"

**为简单起见,这将始终是字符串的格式,始终是3 a后跟空格或')'或3b后跟空格或')'。

用'1'代替'aaa'的每一个出现的最佳方法是什么,并且'结束字符串中'bbb'与'0'的每次出现应该是这样的:

"(1 and 0 or (1 or 1 or 0))"

编辑让我更具体一点:

char* blah = (char *) malloc (8);
sprintf(blah, "%s", "aaa bbb");

blah = replace(blah);

如何编写替换以便分配空间并存储新字符串

"1 0"

6 个答案:

答案 0 :(得分:4)

最有效的方法是使用POSIX的正则表达式族。一些实现将为模式构建适当的自动机。另一种方法是重复使用KMP或Boyer-Moore搜索,但是你必须多次扫描字符串,效率较低。另外,给出这样的输入你想得到什么结果:aa = 1,ab = 2,bb = 3 on string“aabb”?

顺便说一下,当你实现这个功能时,一个更干净的解决方案是分配一个新的动态C字符串,而不是在替换时修改原始字符串。您可以实施就地替换,但这会复杂得多。

regex_t r; regmatch_t match[2]; int last = 0;
regcomp(&r, "(aaa|bbb)", REG_EXTENDED);
insert(hashtable, "aaa", "0"); insert(hashtable, "bbb", "1");
while (regexec(&r, oristr, 1, match, 0) != REG_NOMATCH) {
  char *val;
  strncat(newstr, oristr + last, match->rm_so);
  lookup(hashtable, oristr + match->rm_so, match->rm_eo - match->rm_so, &val);
  last = match->rm_eo;
  strncat(newstr, val);
}
strcat(newstr, oristr + last);
oristr = realloc(oristr, strlen(newstr));
strcpy(oristr, newstr); free(newstr); regfree(&r);

在实际实现中,您应该动态更改newstr的大小。你应该记录newstr的结尾,而不是使用strcat / strlen。源代码可能有问题,因为我还没有真正尝试过。但这个想法就在那里。这是我能想到的最有效的实现。

答案 1 :(得分:1)

对于这种特定情况,一个简单的while / for循环可以解决问题。但它看起来像是一个家庭作业问题,所以我不会为你明确写出来。如果需要更通用的字符串操作,我会使用pcre。

答案 2 :(得分:1)

这里没有内存限制:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* ---------------------------------------------------------------------------
  Name       : replace - Search & replace a substring by another one. 
  Creation   : Thierry Husson, Sept 2010
  Parameters :
      str    : Big string where we search
      oldstr : Substring we are looking for
      newstr : Substring we want to replace with
      count  : Optional pointer to int (input / output value). NULL to ignore.  
               Input:  Maximum replacements to be done. NULL or < 1 to do all.
               Output: Number of replacements done or -1 if not enough memory.
  Returns    : Pointer to the new string or NULL if error.
  Notes      : 
     - Case sensitive - Otherwise, replace functions "strstr" by "strcasestr"
     - Always allocate memory for the result.
--------------------------------------------------------------------------- */
char* replace(const char *str, const char *oldstr, const char *newstr, int *count)
{
   const char *tmp = str;
   char *result;
   int   found = 0;
   int   length, reslen;
   int   oldlen = strlen(oldstr);
   int   newlen = strlen(newstr);
   int   limit = (count != NULL && *count > 0) ? *count : -1; 

   tmp = str;
   while ((tmp = strstr(tmp, oldstr)) != NULL && found != limit)
      found++, tmp += oldlen;

   length = strlen(str) + found * (newlen - oldlen);
   if ( (result = (char *)malloc(length+1)) == NULL) {
      fprintf(stderr, "Not enough memory\n");
      found = -1;
   } else {
      tmp = str;
      limit = found; /* Countdown */
      reslen = 0; /* length of current result */ 
      /* Replace each old string found with new string  */
      while ((limit-- > 0) && (tmp = strstr(tmp, oldstr)) != NULL) {
         length = (tmp - str); /* Number of chars to keep intouched */
         strncpy(result + reslen, str, length); /* Original part keeped */ 
         strcpy(result + (reslen += length), newstr); /* Insert new string */
         reslen += newlen;
         tmp += oldlen;
         str = tmp;
      }
      strcpy(result + reslen, str); /* Copies last part and ending nul char */
   }
   if (count != NULL) *count = found;
   return result;
}


/* ---------------------------------------------------------------------------
   Samples
--------------------------------------------------------------------------- */
int main(void)
{
   char *str, *str2;
   int rpl;

   /* ---------------------------------------------------------------------- */
   /* Simple sample */
   rpl = 0; /* Illimited replacements */
   str = replace("Hello World!", "World", "Canada", &rpl);
   printf("Replacements: %d\tResult: [%s]\n\n", rpl, str);
   /* Replacements: 1        Result: [Hello Canada!] */
   free(str);

   /* ---------------------------------------------------------------------- */
   /* Sample with dynamic memory to clean */
   rpl = 0; /* Illimited replacements */
   str = strdup("abcdef");
   if ( (str2 = replace(str, "cd", "1234", &rpl)) != NULL ) {
      free(str);
      str = str2;
   }
   printf("Replacements: %d\tResult: [%s]\n\n", rpl, str);
   /* Replacements: 1        Result: [ab1234ef] */
   free(str);

   /* ---------------------------------------------------------------------- */
   /* Illimited replacements - Case sensitive & Smaller result */
   str = replace("XXXHello XXXX world XX salut xxx monde!XXX", "XXX", "-",NULL);
   printf("Result: [%s]\n\n", str);
   /* Result: [-Hello -X world XX salut xxx monde!-] */
   free(str);

   /* ---------------------------------------------------------------------- */
   rpl = 3; /* Limited replacements */
   str = replace("AAAAAA", "A", "*", &rpl);
   printf("Replacements: %d\tResult: [%s]\n\n", rpl, str);
   /* Replacements: 3        Result: [***AAA] */
   free(str);

  return 0;
}

答案 3 :(得分:0)

这绝不是世界上最优雅的解决方案,并且它还假设结束字符串总是比原始字符串更小,哦,我对转换进行了硬编码,但希望它或多或少地指向你正确的方向或让你有一个想法跳出:

char* replace( char *string ) {
    char *aaa = NULL;
    char *bbb = NULL;
    char *buffer = malloc( strlen( string ) );
    int length = 0;
    aaa = strstr( string, "aaa" );
    bbb = strstr( string, "bbb" );
    while ( aaa || bbb ) {
        if ( aaa && (bbb || aaa < bbb ) ) {
            char startToHere = aaa - string;
            strncpy( buffer, string, startToHere );
            string += startToHere;
            length += startToHere;
            buffer[length] = '1';
        }
        else if ( bbb ) {
            char startToHere = aaa - string;
            strncpy( buffer, string, startToHere );
            string += startToHere;
            length += startTohere;
            buffer[length] = '0';
        }
        aaa = strstr( string, "aaa" );
        bbb = strstr( string, "bbb" );
    }
    buffer[length] = '\0';
    string = realloc( string, length );
    strcpy( string, buffer );
    free( buffer );

    return string;
}

免责声明,我甚至没有对此进行测试,但它至少应该朝着你想要的方向发展。

答案 4 :(得分:0)

这是FSM的作业!

#include <assert.h>
#include <stdio.h>
#include <string.h>

/*
//     | 0          | 1             | 2              | 3             | 4              |
// ----+------------+---------------+----------------+---------------+----------------+
// 'a' | 1          | 2             | ('1') 0        | ('b') 1       | ('bb') 1       |
// 'b' | 3          | ('a') 3       | ('aa') 3       | 4             | ('0') 0        |
// NUL | (NUL) halt | ('a'NUL) halt | ('aa'NUL) halt | ('b'NUL) halt | ('bb'NUL) halt |
// (*) | (*) 0      | ('a'*) 0      | ('aa'*) 0      | ('b'*) 0      | ('bb'*) 0      |
*/

void chg_data(char *src) {
  char *dst, ch;
  int state = 0;
  dst = src;
  for (;;) {
    ch = *src++;
    if (ch == 'a' && state == 0) {state=1;}
    else if (ch == 'a' && state == 1) {state=2;}
    else if (ch == 'a' && state == 2) {state=0; *dst++='1';}
    else if (ch == 'a' && state == 3) {state=1; *dst++='b';}
    else if (ch == 'a' && state == 4) {state=1; *dst++='b'; *dst++='b';}
    else if (ch == 'b' && state == 0) {state=3;}
    else if (ch == 'b' && state == 1) {state=3; *dst++='a';}
    else if (ch == 'b' && state == 2) {state=3; *dst++='a'; *dst++='a';}
    else if (ch == 'b' && state == 3) {state=4;}
    else if (ch == 'b' && state == 4) {state=0; *dst++='0';}
    else if (ch == '\0' && state == 0) {*dst++='\0'; break;}
    else if (ch == '\0' && state == 1) {*dst++='a'; *dst++='\0'; break;}
    else if (ch == '\0' && state == 2) {*dst++='a'; *dst++='a'; *dst++='\0'; break;}
    else if (ch == '\0' && state == 3) {*dst++='b'; *dst++='\0'; break;}
    else if (ch == '\0' && state == 4) {*dst++='b'; *dst++='b'; *dst++='\0'; break;}
    else if (state == 0) {state=0; *dst++=ch;}
    else if (state == 1) {state=0; *dst++='a'; *dst++=ch;}
    else if (state == 2) {state=0; *dst++='a'; *dst++='a'; *dst++=ch;}
    else if (state == 3) {state=0; *dst++='b'; *dst++=ch;}
    else if (state == 4) {state=0; *dst++='b'; *dst++='b'; *dst++=ch;}
    else assert(0 && "this didn't happen!");
  }
}

int main(void) {
  char data[] = "(aaa and bbb or (aaa or aaa or bbb))";
  printf("Before: %s\n", data);
  chg_data(data);
  printf(" After: %s\n", data);
  return 0;
}

答案 5 :(得分:-3)

您可以使用std::findstd::replace函数为每次替换尝试循环。 您将找到有关std :: string here的更多信息。