繁体   English   中英

不用string.h库替换C中的一个字符串

[英]Replace a string in C without string.h library

我想制作一个 function,它将在不使用<string.h>库的情况下替换两个字符串。 为了实现这一点,我使用了 6 个手动编写的函数,它们共同完成了这项任务。 这段代码有一个小问题,它不检查将被替换的字符串是否是完全等于替换字符串的单词。

例如:

char s[] = "Why is ostring in C so hard",
     change_what[] = "string",
     into_what[] = "pointers";

OUTPUT 应该是:

"Why is ostring in C so hard"

因为"ostring"并不完全等于"string"

我的 output 是:

"Why are opointers in C so hard"

代码:

#include <stdio.h>

int compare(char *x, char *y)
{
    while (*x != '\0' || *y != '\0')
    {
        if (*x == *y)
        {
            x++;
            y++;
        }
        // if they are not equal
        else if ((*x == '\0' && *y != '\0') || (*x != '\0' && *y == '\0') ||
                 *x != *y)
        {
            return 0;
        }
    }
    return 1;
}

int lenght(char *a)
{
    char *b;
    for (b = a; *a; a++)
        ;
    return a - b;
}

char *substring(char *main_string, char *substring) {
    while (*main_string != '\0') {
        char *p = main_string;
        char *q = substring;
        while (*p++ == *q++) {
            if (*p == ' ' || *p == '\0')
               if (*q == '\0') {
                   return main_string;
            }
        }
        main_string++;
    }
    return NULL;
}

void replace_string_add(char *s, char *change_what, char *into_what,
                        int shift)
{
    char *i_pointer = into_what;
    char *c_pointer = change_what;
    char *position = substring(s, change_what);
    while (position != NULL)
    {
        char *end = position;
        while (*end != '\0')
        {
            end++;
        }
        while (end > position)
        {
            *(end + shift) = *end;
            end--;
        }
        while (*into_what != '\0')
        {
            *position++ = *into_what++;
        }
        position = substring(s, change_what);
        into_what = i_pointer;
        change_what = c_pointer;
    }
}

void replace_string_remove(char *s, char *change_what, char *into_what,
                           int shift)
{
    char *i_pointer = into_what;
    char *c_pointer = change_what;
    char *position = substring(s, change_what);
    while (position != NULL)
    {
        char *temp = position;
        while (*(temp + shift) != '\0')
        {
            *temp = *(temp + shift);
            temp++;
        }
        *temp = '\0';
        while (*into_what != '\0')
        {
            *position++ = *into_what++;
        }
        position = substring(s, change_what);
        into_what = i_pointer;
        change_what = c_pointer;
    }
}

void replace_string(char *s, char *change_what, char *into_what)
{
    int shift = lenght(into_what) - lenght(change_what);
    if (compare(change_what, into_what) == 0)
    {
        if (shift >= 0)
        {
            replace_string_add(s, change_what, into_what, shift);
        }
        else
        {
            replace_string_remove(s, change_what, into_what, -shift);
        }
    }
}

int main()
{
    char s[] = "Why is ostring in C so hard",
         change_what[] = "string",
         into_what[] = "pointers";
    replace_string(s, change_what, into_what);
    printf("\"%s\"", s);
    return 0;
}

如果字符串是"Why is strings in C so hard"程序将正确工作,因为它检查最后一个字符是' '还是'\0'

"Why is ostring in C so hard"是行不通的,因为它不检查第一个字符。 你能帮我修改这段代码来检查第一个字符吗?

  • 注意:不允许使用辅助字符串和动态分配

您的程序有多个问题:

  • compare function里面有很多冗余代码,可以简化为:

     int compare(const char *x, const char *y) { while (*x;= '\0' || *y;= '\0') { if (*x == *y) { x++; y++; } else { return 0; } } return 1; }

    甚至更进一步:

     int compare(const char *x, const char *y) { while (*x++ == *y++) { if (x[-1] == '\0') return 1; } return 0; }
  • lenght function 应命名为length

  • substring检查 substring 结束后的空格,但不检查开始前的空格。 如果 substring 匹配main_string的结尾,它也有未定义的行为,因为将访问超出 null 终止符的字符。 这是修改后的版本:

     char *substring(char *main_string, const char *substring) { char *p = main_string; char last = ' '; while (*p;= '\0') { if (last == ' ') { size_t i = 0; while (substring[i];= '\0' && p[i] == substring[i]) { i++; } if (substring[i] == '\0' && (p[i] == ' ' || p[i] == '\0')) { return p; } } last = *p++; } return NULL; }
  • replace_string_addreplace_string_remove中, c_pointer是无用的,使用i_pointer复制替换比修改into_what并恢复它更容易混淆。

另请注意, main_string参数必须有足够的空间用于替换,如果change_what字符串为"ostring" ,则示例中不会出现这种情况。

这是修改后的版本:

#include <stdio.h>

int compare(const char *x, const char *y) {
    while (*x++ == *y++) {
        if (x[-1] == '\0')
            return 1;
    }
    return 0;
}

int length(const char *a) {
    const char *b;
    for (b = a; *a; a++)
        continue;
    return a - b;
}

char *substring(char *main_string, const char *substring, int len) {
    char *p = main_string;
    char last = ' ';
    while (*p != '\0') {
        if (last == ' ') {
            int i = 0;
            while (i < len && p[i] == substring[i]) {
                i++;
            }
            if (i == len && (p[i] == ' ' || p[i] == '\0')) {
                return p;
            }
        }
        last = *p++;
    }
    return NULL;
}

char *replace_string(char *s, const char *change_what, const char *into_what) {
    int what_len = length(change_what);
    int into_len = length(into_what);
    int shift = into_len - what_len;
    int i;
    char *pos = s;

    if (shift == 0 && compare(change_what, into_what))
        return s;

    while (*pos && (pos = substring(pos, change_what, what_len)) != NULL) {
        if (shift > 0) {
            for (i = length(pos); i >= what_len; i--) {
                pos[i + shift] = pos[i];
            }
        } else
        if (shift < 0) {
            for (i = into_len; ((pos[i] = pos[i - shift]) != '\0'; i++) {
                continue;
            }
        }
        for (i = 0; i < into_len; i++) {
            *pos++ = into_what[i];
        }
        if (*pos == ' ') {
            pos++;
        }
    }
    return s;
}

int main() {
    char s[100] = "Why is ostring in C so hard";
    printf("\"%s\"\n", replace_string(s, "string", "pointer"));
    printf("\"%s\"\n", replace_string(s, "ostring", "pointers"));
    printf("\"%s\"\n", replace_string(s, "is", "are"));
    printf("\"%s\"\n", replace_string(s, "hard", "cool"));
    printf("\"%s\"\n", replace_string(s, "pointers", "strings"));
    printf("\"%s\"\n", replace_string(s, "in C", ""));
    printf("\"%s\"\n", replace_string(s, "", "in C++ not"));
    printf("\"%s\"\n", replace_string(s, "", ""));
    return 0;
}

Output:

"Why is ostring in C so hard"
"Why is pointers in C so hard"
"Why are pointers in C so hard"
"Why are pointers in C so cool"
"Why are strings in C so cool"
"Why are strings  so cool"
"Why are strings in C++ not so cool"
"Why are strings in C++ not so cool"

好的,我认为为此使用字符串标记器更容易。 下面的代码首先将 s 复制到 s2 中,然后在每个空格处放置一个 '\0' 并跟踪有多少个单词。 第一个 for 循环。 然后清除 s 并循环通过 s2 在每个 '\0' 标记处停止并检查每个单词是否等于您的替换词。 如果匹配,则复制回替换词,否则复制原始词。

#include <stdio.h>

static void cat(char *d, char *s)
{
    char *p;
    for (p = d; *p; p++);
    
    for (char *p2 = s; *p2;)
      *p++ = *p2++;
    *p = 0;
}

static int cmp(char *s1, char *s2)
{
    char *p1 = s1, *p2 = s2;
    
    while (*p1 && *p2 && *p1 == *p2)
    {
        p1++;
        p2++;
    }

    if (*p1 == 0 && *p2 == 0) return 0;
    
    return -1;
}

int main()
{
    char s[100]="Why are strings in C so hard",change_what[]="strings", into_what[]="pointers";
    
    char s2[100];
    
    for (char *p = s, *p2 = s2; *p2=*p; p++, p2++);
    
    int countwords = 0;
    
    for (char *p = s2; *p; p++)
       if (*p == ' ') { *p = '\0'; countwords++; }

    int current = 0;
    
    char *s3 = s2;
    *s = '\0';
    
    while (current <= countwords)
    {
        char *p = s3;
        for (; *p; p++);
        
        if (cmp(s3, change_what) == 0)
            cat(s, into_what);
        else
            cat(s, s3);
            
        cat(s, " ");
            
        s3 = p + 1;

        current++;
    }
    
    printf("%s\n", s);
    
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM