2013-09-22 4 views
1

У меня есть следующий код:заменить маркер в строке

char *repl_word(char *word, char *repl) 
{ 
    const char *p1 = strstr(word,"<")+1; 
    const char *p2 = strstr(p1,">"); 
    size_t len = p2-p1; 
    char *src = (char*)malloc(len+1); 
    if (src == NULL) 
     return word; 
    strncpy(src,p1,len); 
    src[len] = '\0'; 
    char *find = "test"; 
    char *found; 
    char *res = malloc(strlen(src) + strlen(repl) - strlen(find) + 1); 
    if (res == NULL) 
     return src; 
    found = strstr(src, find); 

    if (found == NULL){ 
     free(res); 
     return src; 
    } 
    res[0] = '\0'; 
    strncpy(res, src, (size_t)(found - src)); 
    strcat(res, repl); 
    strcat(res, found + strlen(find)); 
    return res; 
} 

, который работает хорошо, но только для первого вхождения "test". Если слово "<testtesttest1234>" не заменяет все.

Как я могу заставить его заменить все вхождения теста в строковое слово с помощью repl?

+0

Это потому, что вы этого не сделаете петля. –

+0

да, я знаю, но я не знаю, как добавить цикл, чтобы не повлиять на malloc. Должен ли я использовать realloc или smth? –

+0

Размер 'malloc'd не должен быть точного размера. Вы можете просто игнорировать все после того, как вы «переместите» строку слева (для замены) и добавьте нулевой символ. –

ответ

1

Я собираюсь игнорировать код, который удаляет <> и просто сосредоточиться на ядре вопроса.

Если вы не знаете заранее длину строки и замены, то у вас есть несколько вариантов:

  1. Подсчитайте количество матчей первого и использовать, чтобы отработать пространство requried
  2. используйте realloc в цикле, чтобы изменить объем памяти, выделенной
  3. Start с умной догадкой в ​​размере, а затем использовать перераспределить в соответствии с требованиями
  4. использования фиксированных буферов размера и просто ошибкой, если мы бежим

Первый - это самый простой способ, который вы хотите использовать, зависит от ваших требований к производительности (четыре быстрее всего стоят за счет увеличения объема памяти, если вы хорошо разбираетесь в максимальном размере строки, три, вероятно, следующий быстрый, если у вас есть хорошее представление о среднем числе матчей).

Реализация простейший метод только требует две петли, один, чтобы найти спички, то один, чтобы сделать замену:

char *strreplace(char *src, char* find, char *repl) 
{ 
    char *target; // Will store our new string 
    char *final;  // Will use to store the pointer of the final string 
    char *str = src; // Will use for searching 
    int matches = 0; 

    // First count the matches (if strlen(repl) <= strlen(word) 
    // you could skip this and just allocate strlen(src) 

    while (str = strstr(str, find)) { 
    matches ++; 
    str++; 
    } 

    target = malloc(1 + strlen(src) + 
       (sizeof(char) * (matches * 
         (strlen(repl) - strlen(find)) 
        ))); 
    if (target == NULL) { 
    return src; // Or NULL, or whatever to indicate an error 
    } 

    final = target; 

    // Now copy everything 
    str = src; 
    while (str = strstr(str, find)) { 

    // Copy string before the match 
    if (str > src) { 
     strncpy(target, src, (str - src)); 
     target += (str - src); 
    src += (str - src); 
    } 

    // Copy replacement 
    strncpy(target, repl, strlen(repl)); 

    // Move pointers 
    str++;     // Move past the match in our searching pointer 
    src += strlen(find); // Move past the string in our src 
    target += strlen(repl); // Move past the replacement in our target 

    } 
    // Finally copy the rest of the string, if there's some left 
    if (*src) { 
    strncpy(target, src, strlen(src)); 
    } 

    return final; 
} 

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

Вы можете считать, что и адаптировать его делать то, что вы хотите, некоторые тесты (чтобы попытаться охватить случаи угловые):

printf("%s\n", strreplace("testtesttest1234", "test", "foo")); 
printf("%s\n", strreplace("testtesttest1234", "test", "foobar")); 
printf("%s\n", strreplace("somethingtestsomethingteasesttest", "test", "foobar")); 

Выходы:

foofoofoo1234 
foobarfoobarfoobar1234 
somethingfoobarsomethingteasestfoobar 
+0

Я уже решил его, немного изменив ответ на предложенный дублирующий вопрос, но для вашего времени и усилий я приму свой ответ. Спасибо! –

Смежные вопросы