Как заменить часть строки другой подстрокой - PullRequest
2 голосов
/ 08 мая 2019

Мне нужно заменить строку «on» на «in», функция strstr () возвращает указатель на строку, поэтому я решил, что присвоение нового значения этому указателю будет работать, но это не

#include <stdio.h>
#include <string.h>

int main(void) {
    char *m = "cat on couch";
    *strstr(m, "on") = "in";
    printf("%s\n", m);
}

Ответы [ 3 ]

5 голосов
/ 08 мая 2019

Заменить подстроку на другую легко, если обе подстроки имеют одинаковую длину:

  • найдите положение подстроки с помощью strstr
  • , если она присутствует, используйте memcpy перезаписать его новой подстрокой.
  • назначение указателя с *strstr(m, "on") = "in"; неверно и должно генерировать предупреждение компилятора.Вы бы избежали таких ошибок с gcc -Wall -Werror.
  • , однако отметьте, что вы не можете изменить строковый литерал, вам нужно определить инициализированный массив char, чтобы вы могли его изменить.

Вот исправленная версия:

#include <stdio.h>
#include <string.h>

int main(void) {
    char m[] = "cat on couch";
    char *p = strstr(m, "on");
    if (p != NULL) {
        memcpy(p, "in", 2);
    }
    printf("%s\n", m);
    return 0;
}

Если замена короче, код будет немного сложнее:

#include <stdio.h>
#include <string.h>

int main(void) {
    char m[] = "cat is out roaming";
    char *p = strstr(m, "out");
    if (p != NULL) {
        memcpy(p, "in", 2);
        memmove(p + 2, p + 3, strlen(p + 3) + 1);
    }
    printf("%s\n", m);
    return 0;
}

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

#include <stdio.h>
#include <string.h>

int main(void) {
    char m[30] = "cat is inside the barn";
    char *p = strstr(m, "inside");
    if (p != NULL) {
        memmove(p + 7, p + 6, strlen(p + 6) + 1);
        memcpy(p, "outside", 7);
    }
    printf("%s\n", m);
    return 0;
}

Вот обобщенная функция, которая обрабатывает все случаи:

#include <stdio.h>
#include <string.h>

char *strreplace(char *s, const char *s1, const char *s2) {
    char *p = strstr(s, s1);
    if (p != NULL) {
        size_t len1 = strlen(s1);
        size_t len2 = strlen(s2);
        if (len1 != len2)
            memmove(p + len2, p + len1, strlen(p + len1) + 1);
        memcpy(p, s2, len2);
    }
    return s;
}

int main(void) {
    char m[30] = "cat is inside the barn";

    printf("%s\n", m);
    printf("%s\n", strreplace(m, "inside", "in"));
    printf("%s\n", strreplace(m, "in", "on"));
    printf("%s\n", strreplace(m, "on", "outside"));
    return 0;
}
2 голосов
/ 08 мая 2019

Есть несколько проблем с этим подходом.Во-первых, выключено, m указывает на постоянную память, поэтому при попытке перезаписать память там неопределенное поведение.

Во-вторых, строка: strstr(m, "on") = "in" не собирается менять указанную настрока, но вместо этого переназначить указатель.

Решение:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char m[] = "cat on couch";
    memcpy(strstr(m, "on"), "in", 2);
    printf("%s\n", m);
}

Обратите внимание, что если бы вы только что использовали обычный strcpy, он бы заканчивался нулем после "cat in", поэтому memcpyздесь необходимоstrncpy также будет работать, но вы должны прочитать это обсуждение перед его использованием.

Также следует знать, что если вы имеете дело со строками, которые не являются жестко закодированными константами в вашемПрограмма, вы всегда должны проверять возвращаемое значение strstr, strchr и соответствующие функции для NULL.

1 голос
/ 08 мая 2019

Эта функция выполняет замену общего шаблона для всех экземпляров подстроки со строкой замены.Он выделяет буфер правильного размера для результата.Поведение хорошо определено для случая пустой подстроки, соответствующей семантике javascript replace ().Там, где это возможно, вместо strcpy используется memcpy.

/*
 * strsub : substring and replace substring in strings.
 *
 * Function to replace a substring with a replacement string. Returns a
 * buffer of the correct size containing the input string with all instances
 * of the substring replaced by the replacement string.
 *
 * If the substring is empty the replace string is written before each character
 * and at the end of the string.
 *
 * Returns NULL on error after setting the error number.
 *
 */

char * strsub (char *input, char *substring, char *replace)
{
    int     number_of_matches = 0;
    size_t  substring_size = strlen(substring), replace_size = strlen(replace), buffer_size;
    char    *buffer, *bp, *ip;

/*
 * Count the number of non overlapping substring occurences in the input string. This
 * information is used to calculate the correct buffer size.
 */
    if (substring_size)
    {
        ip = strstr(input, substring);
        while (ip != NULL)
        {
            number_of_matches++;
            ip = strstr(ip+substring_size, substring);
        }
    }
    else
        number_of_matches = strlen (input) + 1;

/*
 * Allocate a buffer of the correct size for the output.
 */
    buffer_size = strlen(input) + number_of_matches*(replace_size - substring_size) + 1;

    if ((buffer = ((char *) malloc(buffer_size))) == NULL)
    {
        errno=ENOMEM;
        return NULL;
    }

/*
 * Rescan the string replacing each occurence of a match with the replacement string.
 * Take care to copy buffer content between matches or in the case of an empty find
 * string one character.
 */
    bp = buffer;
    ip = strstr(input, substring);
    while ((ip != NULL) && (*input != '\0'))
    {
        if (ip == input)
        {
            memcpy (bp, replace, replace_size+1);
            bp += replace_size;
            if (substring_size)
                input += substring_size;
            else
                *(bp++) = *(input++);
            ip = strstr(input, substring);
        }
        else 
            while (input != ip)
                *(bp++) = *(input++);

    }

/*
 * Write any remaining suffix to the buffer, or in the case of an empty find string
 * append the replacement pattern.
 */
    if (substring_size)
        strcpy (bp, input);
    else
        memcpy (bp, replace, replace_size+1);

    return buffer;
}

Для целей тестирования я включаю основную программу, которая использует функцию замены.

    #define BUFSIZE 1024

    char * read_string (const char * prompt)
    {
        char *buf, *bp;

        if ((buf=(char *)malloc(BUFSIZE))==NULL)
        {
            error (0, ENOMEM, "Memory allocation failure in read_string");
            return NULL;
        }
        else
            bp=buf;

        printf ("%s\n> ", prompt);

        while ((*bp=getchar()) != '\n')bp++;
        *bp = '\0';

        return buf;
    }

    int main ()
    {
        char * input_string = read_string ("Please enter the input string");
        char * pattern_string = read_string ("Please enter the test string");
        char * replace_string = read_string ("Please enter the replacement string");

        char * output_string = strsub (input_string, pattern_string, replace_string);

        printf ("Result       :\n> %s\n", output_string);

        free (input_string);
        free (pattern_string);
        free (replace_string);
        free (output_string); 
        exit(0);
    }
...