web-dev-qa-db-ja.com

Cの文字列内のすべての部分文字列を置き換えます

文字列内のすべての部分文字列を置き換える関数をCで作成しようとしています。私は自分の関数を作成しましたが、大きい文字列内の最初の部分文字列でのみ機能します。

これまでのコードは次のとおりです。

void strreplace(char string[], char search[], char replace[]){
    char buffer[100];
    char*p = string;
    while((p=strstr(p, search))){
        strncpy(buffer, string, p-string);
        buffer[p-string] = '\0'; //EDIT: THIS WAS MISSING
        strcat(buffer, replace);
        strcat(buffer, p+strlen(search));
        strcpy(string, buffer);
        p++;
    }
} 

私はCプログラミングに不慣れではありませんが、ここで何かが足りません。

例:入力文字列「mariehas apples has」の場合、「has」を検索して「blabla」に置き換えます

最初の「has」は正しく置き換えられますが、2番目の「has」は正しく置き換えられません。最終出力は「marie blabla apples hasblabla」です。 2番目の「持っている」がまだそこにあることに注意してください。

私は何が間違っているのですか? :)

EDIT Isは現在動作しています。 null終了文字を追加すると、問題が修正されました。結果の文字列は100より大きくなる可能性があることを知っています。これは学校の宿題なので、20文字以上の文字列は使用しません。

6
Erik Blenert

手始めに:

この線

strncpy(buffer, string, p-string);

bufferにコピーされたものに必ずしも0ターミネータを追加する必要はありません。

次の行

strcat(buffer, replace);

ただし、buffer0で終了することに依存しています。

bufferが初期化されておらず、0ターミネーターが後者の行を見逃している可能性が高いため、bufferのメモリを超えて読み取られ、悪名高い未定義の振る舞いが呼び出される可能性があります。

4
alk

あなたがどのアルゴリズムに従おうとしているのか私にはわかりません、それはすべて私には怪しいように見えます。おそらく最も簡単なアプローチは次のとおりです。

  • 「針」の最初の出現を検索します(検索された部分文字列)
  • 最初のオカレンスの前の部分を結果バッファにコピーします
  • 置換文字列を結果バッファに追加します
  • pポインターをインクリメントして、針の直後を指すようにします
  • GOTO 10
void str_replace(char *target, const char *needle, const char *replacement)
{
    char buffer[1024] = { 0 };
    char *insert_point = &buffer[0];
    const char *tmp = target;
    size_t needle_len = strlen(needle);
    size_t repl_len = strlen(replacement);

    while (1) {
        const char *p = strstr(tmp, needle);

        // walked past last occurrence of needle; copy remaining part
        if (p == NULL) {
            strcpy(insert_point, tmp);
            break;
        }

        // copy part before needle
        memcpy(insert_point, tmp, p - tmp);
        insert_point += p - tmp;

        // copy replacement string
        memcpy(insert_point, replacement, repl_len);
        insert_point += repl_len;

        // adjust pointers, move on
        tmp = p + needle_len;
    }

    // write altered string back to target
    strcpy(target, buffer);
}

警告:関数の呼び出し方法にも注意する必要があります。交換用の文字列が針よりも大きい場合、変更された文字列は元の文字列よりも長くなるため、元のバッファが変更された文字列を含むのに十分な長さであることを確認する必要があります。例えば。:

char s[1024] = "marie has apples has";                         
str_replace(s, "has", "blabla");
char *replace_str(char *str, char *orig, char *rep)
{
static char buffer[4096];
char *p;
int i=0;

while(str[i]){
    if (!(p=strstr(str+i,orig)))  return str;
    strncpy(buffer+strlen(buffer),str+i,(p-str)-i);
    buffer[p-str] = '\0';
    strcat(buffer,rep);
    printf("STR:%s\n",buffer);
    i=(p-str)+strlen(orig);
}

return buffer;
}

int main(void)
{
  char str[100],str1[50],str2[50];
  printf("Enter a one line string..\n");
  gets(str);
  printf("Enter the sub string to be replaced..\n");
  gets(str1);
  printf("Enter the replacing string....\n");
  gets(str2);
  puts(replace_str(str, str1, str2));

  return 0;
}

入力:マリーはリンゴを持っています

出力:マリーブラブラリンゴブラブラ

4
StackUser
int replace_str(char* i_str, char* i_orig, char* i_rep)
{
   char l_before[2024];
   char l_after[2024];
   char* l_p;
   int l_origLen;

   l_origLen = strlen(i_orig);
   while (l_p = strstr(i_str, i_orig)) {
      sprintf(l_before ,"%.*s" ,l_p - i_str ,i_str);
      sprintf(l_after ,"%s" ,l_p + l_origLen);
      sprintf(i_str ,"%s%s%s" ,l_before ,i_rep ,l_after);
   }
   return(strlen(i_str));
}
0
Claudio