как заменить подстроку с разной длиной в C?

#c #string

Вопрос:

Ситуация следующая: В первой строке введите строку, затем следующие строки — «команда». 2 типа команд » p » и «s», » p «означает печать строки,» s » означает подстановку. например, Введите строку aaabbbcccqwerdd, затем введите sbqwerbkkk (s означает подстановку, b действует как разделитель, поэтому это означает замену qwer в строке на kkk) Ожидаемый результат должен быть aaabbbccckkkdd, но вместо этого я получил aaabbbccckkkrdd Какая-нибудь помощь?

 #include lt;stdio.hgt; #include lt;stdlib.hgt; #include lt;string.hgt; #define MAXLEN 1023 int main() {  char str[MAXLEN];  scanf("%s", str);  char command[MAXLEN];  while (scanf("%s", command) != EOF) {  if (command[0] == 'p') {  printf("%sn", str); }  else if (command[0] == 's') {  char delimiter[] = {"0"};  strncpy(delimiter, command 1, 1);  char *a = command;  a = strtok(command, delimiter);  a = strtok(NULL, delimiter);  char *b = command;  b = strtok(NULL, delimiter);  int alength = strlen(a);  int blength = strlen(b);  char *bereplaced = strstr(str, a);  if (bereplaced == NULL) {  continue; }  int aindex = bereplaced - str;  strncpy(str   aindex, b, blength);  }  }  return 0; }  

Комментарии:

1. Ручка и бумага-ваши друзья здесь! Нарисуйте строки на бумаге, используя квадраты для отдельных символов. Используйте это, чтобы определить индексы или указатели, из которых вам нужно скопировать каждую часть каждой строки, и как получить длину. Сделайте это для нескольких разных строк и не забудьте включить как меньшие, равные, так и большие замены. Как только это начнет работать, определите функции, необходимые для получения индексов или указателей и длин, и начните реализацию. И не волнуйтесь, код никогда не будет выглядеть очень красиво. И выделите его в отдельную функцию, чтобы сделать его более простым и удобным в обслуживании.

2. С точки зрения реализации я бы на самом деле рекомендовал две функции «замены»: одну для замены с использованием индексов; И одну с использованием разделителей. Функция-разделитель находит индексы и использует первую функцию на основе индексов.

3. Неправильно выполнять strtok один раз для одного разделителя, а другой раз для другого разделителя, так как первый вызов изменяет начальный ввод.

Ответ №1:

Здесь многое может пойти не так, но главная проблема заключается в копировании из исходной строки в саму себя, может возникнуть перекрытие памяти. Вместо этого объявите новый буфер для результата операции поиска/замены.

Вы можете определить отдельную find_replace функцию следующим образом:

 char* find_replace(const char* src, const char* find, const char* replace) {  if (!src) return NULL;  char* find_ptr = strstr(src, find); if (!find_ptr) return NULL;  int find_start = find_ptr - src;  int find_length = strlen(find);  char* result = malloc(strlen(src)   strlen(replace)   1);  strncpy(result, src, find_start);  strcpy(result   find_start, replace);  strcat(result, find_ptr   find_length);  return result; }  int main()  {  char source[] = "aaabbbcccqwerdd";  char command[] = "sbqwerbkkk";  if (command[0] != 's') return 0;  char delimiter[] = { "0" };  delimiter[0] = command[1];   char* find = strtok(command, delimiter); if (!find) return 0;  find = strtok(NULL, delimiter); if (!find) return 0;   char* replace = strtok(NULL, delimiter); if (!replace) return 0;  char* result = find_replace(source, find, replace);  if (!result) return 0;  printf("%sn", result);  free(result);  return 0; }  

Ответ №2:

Вот еще одно решение. Он выполняет подстановку непосредственно во входную строку с помощью:

  1. Используется memmove для перемещения конечной части исходной строки в ее конечное местоположение
  2. Используется strncpy для копирования подстроки-замены в ее конечное расположение

Нравится:

 #include lt;stdio.hgt; #include lt;string.hgt;  #define MAXLEN 1023  int main(void)  {  char str[MAXLEN] = "aaabbbcccqwerdd";  char command[MAXLEN] = "sbqwerbkkk";  printf("COMMAND : %sn", command);  printf("TEXT BEFORE : %sn", str);   char* pfind = command   2; // skip initial sb  char* psub = strchr(pfind, 'b'); // find delimiter  *psub = ''; // terminate replace string    psub; // point to substitute substring  size_t flen = strlen(pfind); // calculate length  size_t slen = strlen(psub); // calculate length  char* p = strstr(str, pfind); // find location of replace string  size_t sc = strlen(p); // calculate length  memmove(p   slen, p   flen, sc - flen   1); // Move trailing part  strncpy(p, psub, slen); // Put in substitute substring    printf("TEXT AFTER : %sn", str);   return 0; }  

Выход:

 COMMAND : sbqwerbkkk TEXT BEFORE : aaabbbcccqwerdd TEXT AFTER : aaabbbccckkkdd  

Раскрыватель

Чтобы сократить пример кода, приведенный выше код слепо верит в то, что команда и исходная строка образуют законную замену и что для результата достаточно памяти.

В реальном коде вам нужно это проверить. Например, проверьте это strchr и strstr не возвращает значение NULL.