Что такое функция для замены строки в C? - PullRequest
81 голосов
/ 23 апреля 2009

Учитывая строку (char *), я хочу найти все вхождения подстроки и заменить ее альтернативной строкой. Я не вижу какой-либо простой функции, которая достигает этого в

Ответы [ 18 ]

75 голосов
/ 23 апреля 2009

Оптимизатор должен исключить большинство локальных переменных. Указатель tmp предназначен для того, чтобы strcpy не проходил строку, чтобы найти ноль. tmp указывает на конец результата после каждого вызова. (См. Алгоритм художника Шлемеля , почему 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;
}
19 голосов
/ 23 апреля 2009

Это не предусмотрено в стандартной библиотеке C, потому что, учитывая только символ *, вы не можете увеличить объем памяти, выделенной для строки, если строка замены длиннее, чем строка, подлежащая замене.

Вы можете сделать это проще, используя std :: string, но даже там, ни одна функция не сделает это за вас.

8 голосов
/ 23 апреля 2009

Вот пример кода, который это делает.

#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;
}
8 голосов
/ 23 апреля 2009

Поскольку строки в C не могут динамически расти, замена на месте обычно не работает. Поэтому вам нужно выделить место для новой строки, в которой достаточно места для вашей замены, а затем скопировать части из оригинала и замены в новую строку. Для копирования частей вы должны использовать strncpy .

8 голосов
/ 23 апреля 2009

Нет ни одного.

Вам нужно свернуть свои собственные, используя что-то вроде strstr и strcat или strcpy.

8 голосов
/ 23 апреля 2009

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

Если то, что вы хотите, чтобы replace_with было той же длины, что и то, что вы хотите replace, то, вероятно, лучше использовать новый буфер для копирования новой строки.

4 голосов
/ 03 июня 2013
// 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);
}
3 голосов
/ 04 февраля 2014

Функция repl_str () на creativeandcritical.net работает быстро и надежно. На этой странице также имеется широкий строковый вариант repl_wcs () , который можно использовать со строками Unicode, включая те, которые закодированы в UTF-8, через вспомогательные функции - демонстрационный код связан со страницей. Запоздалое полное раскрытие: я являюсь автором этой страницы и функций на ней.

3 голосов
/ 10 марта 2015

Мне кажется, что большинство предлагаемых функций трудно понять, поэтому я придумал следующее:

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

вывод должен быть свободным

1 голос
/ 13 декабря 2016
/*замена символа в строке*/
char* replace_char(char* str, char in, char out) {
    char * p = str;

    while(p != '\0') {
        if(*p == in)
            *p == out;
        ++p;
    }

    return str;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...