如何用另一个子字符串替换字符串的一部分

时间:2019-05-08 14:58:25

标签: c string.h

我需要将字符串“ 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 个答案:

答案 0 :(得分:4)

如果两个子串的长度相同,则用另一个子串替换很容易:

  • 使用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;
}

答案 1 :(得分:2)

此方法存在一些问题。首先,关闭swapouts指向只读内存,因此尝试覆盖那里的内存是未定义的行为。

第二行:$ top -l 1 | head Processes: 797 total, 4 running, 1 stuck, 792 sleeping, 1603 threads 2019/05/08 09:48:40 Load Avg: 54.32, 41.08, 34.69 CPU usage: 62.2% user, 36.89% sys, 1.8% idle SharedLibs: 258M resident, 65M data, 86M linkedit. MemRegions: 78888 total, 6239M resident, 226M private, 2045M shared. PhysMem: 15G used (2220M wired), 785M unused. VM: 3392G vsize, 1299M framework vsize, 0(0) swapins, 0(0) swapouts. Networks: packets: 24484543/16G in, 24962180/7514M out. Disks: 21281572/769G read, 20527776/242G written. 不会更改指向的字符串,而是重新分配指针。

解决方案:

$ df -h
Filesystem                                            Size  Used Avail Use% Mounted on
/dev/disk1s1                                          466G  444G   19G  97% /
/dev/disk1s4                                          466G  3.1G   19G  14% /private/var/vm
/dev/disk2s1                                          932G  546G  387G  59% /Volumes/usbhd
com.apple.TimeMachine.2019-05-06-225547@/dev/disk1s1  466G  441G   19G  96% /Volumes/com.apple.TimeMachine.localsnapshots/Backups.backupdb/py???s MacBook Air/2019-05-06-225547/Macintosh HD
com.apple.TimeMachine.2019-05-02-082105@/dev/disk1s1  466G  440G   19G  96% /Volumes/com.apple.TimeMachine.localsnapshots/Backups.backupdb/py???s MacBook Air/2019-05-02-082105/Macintosh HD

请注意,如果您只是使用普通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也可以使用,但是在使用this discussion之前,您应该先阅读它。

还应该知道,如果要处理程序中不是硬编码常量的字符串,则应始终检查"cat in"memcpy的返回值以及与之相关的函数strncpy

答案 2 :(得分:1)

此函数使用替换字符串对子字符串的所有实例执行通用模式替换。它为结果分配正确大小的缓冲区。对于与javascript replace()语义相对应的空子字符串的情况,行为已得到很好的定义。尽可能使用memcpy代替strcpy。

/*
 * 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);
    }