Делать то, что вы хотите, становится немного сложнее, потому что вам нужно работать со сценариями, в которых:
- замена короче оригинала - так что вам понадобитсяпереместить остаток строки, следуя тексту замены, чтобы не оставлять пустого места;
- замена имеет ту же длину , что и оригинал - простой случай, просто перезаписать оригинал с заменой;и, наконец,
- замена длиннее, чем оригинал - где вы должны проверить исходную строку, плюс разница длины замены все равно будет помещаться в хранилище для исходной строки, вы должны скопировать конецстрока во временный буфер перед выполнением замены, а затем добавьте в конец оставшуюся часть строки во временном буфере.
strtok
некоторые недостатки здесь из-за внесения изменений в исходныйстрока во время процесса токенизации.(вы можете просто сделать копию, но если вы хотите заменить на месте, вам нужно посмотреть дальше).Комбинация strstr
и strcspn
позволяет вам более эффективно работать с исходной строкой при поиске конкретной строки поиска в оригинале.
strcspn
может использоваться как strtok
с набором разделителей для предоставления длины текущего найденного токена (чтобы убедиться, что strstr
не соответствует вашему поисковому запросу как менеевключенная подстрока более длинного слова, например tree
в trees
). Затем становится простым циклом с strstr
и проверкой длины токена с помощью strcspn
, а затем просто применением одного изтри приведенных выше случая.
Краткий пример реализации с комментариями, включенными в строку, чтобы помочь вам следовать далее:
#include <stdio.h>
#include <string.h>
#define MAXLIN 100
void wordreplace (char *str, const char *srch,
const char *repl, const char *delim)
{
char *p = str; /* pointer to str */
size_t lenword, /* length of word found */
lenstr = strlen (str), /* length of total string */
lensrch = strlen (srch), /* length of search word */
lenrepl = strlen (repl); /* length of replace word */
while ((p = strstr (p, srch))) { /* srch exist in rest of string? */
lenword = strcspn (p, delim); /* get length of word found */
if (lenword == lensrch) { /* word len match search len */
if (lenrepl == lensrch) /* if replace is same len */
memcpy (p, repl, lenrepl); /* just copy over */
else if (lenrepl > lensrch) { /* if replace is longer */
/* check that additional lenght will fit in str */
if (lenstr + lenrepl - lensrch > MAXLIN - 1) {
fputs ("error: replaced length would exeed size.\n",
stderr);
return;
}
if (!p[lenword]) { /* if no following char */
memcpy (p, repl, lenrepl); /* just copy replace */
p[lenrepl] = 0; /* and nul-terminate */
}
else { /* store rest of line in buffer, replace, add end */
char endbuf[MAXLIN]; /* temp buffer for end */
size_t lenend = strlen (p + lensrch); /* end length */
memcpy (endbuf, p + lensrch, lenend + 1); /* copy end */
memcpy (p, repl, lenrepl); /* make replacement */
memcpy (p + lenrepl, endbuf, lenend); /* add end after */
}
}
else { /* otherwise replace is shorter than search */
size_t lenend = strlen (p + lenword); /* get end length */
memcpy (p, repl, lenrepl); /* copy replace */
/* move end to after replace */
memmove (p + lenrepl, p + lenword, lenend + 1);
}
}
}
}
int main (int argc, char **argv) {
char str[MAXLIN] = "apple tree house in the elm tree";
const char *search = argc > 1 ? argv[1] : "tree",
*replace = argc > 2 ? argv[2] : "12",
*delim = " \t\n";
wordreplace (str, search, replace, delim);
printf ("str: %s\n", str);
}
Пример использования / Вывод
Ваша замена "tree"
на "12"
пример в "apple tree house in the elm tree"
:
$ ./bin/wordrepl_strstr_strcspn
str: apple 12 house in the elm 12
Простая замена такой же длины "tree"
на "core"
, например
$ ./bin/wordrepl_strstr_strcspn tree core
str: apple core house in the elm core
«больше, чем», заменить "tree"
на "bobbing"
:
$ ./bin/wordrepl_strstr_strcspn tree bobbing
str: apple bobbing house in the elm bobbing
Существует много разных способов решения этой проблемы, поэтому ни один из них не является правильным.Ключ должен сделать это понятным и достаточно эффективным.Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.