【问题标题】:C: If a substring exists inside a string, then change the small letters in the string to capital lettersC:如果字符串中存在子字符串,则将字符串中的小写字母改为大写字母
【发布时间】:2019-06-08 18:49:20
【问题描述】:

我正在编写一个程序来将 C 中的字符串中的子字符串大写。

这里有一些例子来说明我的预期输出:

String:    "hello world"
Substring: "wo"
Output:    "hello WOrld"
String:    "I don't know how to do this"
Substring: "do" 
Output:    "I DOn't know how to DO this"
String:    "mouse is useful thing"
Substring: "use" 
Output:    "moUSE is USEful thing"
String:    "replace occurrences of 'r'"
Substring: "r" 
Output:    "Replace occuRRences of 'R'"

基本上,子字符串存在于字符串中的任何地方,在原始字符串中都大写。

这是我的代码:

void replaceSubstring(char *str, char *substr) {
    char *p = str;
    char *k = substr;
    int substringLength = strlen(k);

    while (*p)
    {
        if (strncmp(p, k, substringLength) == 0)
        {
            for (p; p < p + substringLength; p++)
            {
                *p = *p - 32;
            }
        }
        p++;
    }
    puts(p);
    printf("\n"); 
}

但是,我的代码崩溃了。我的方法是在字符不是'\0' 时循环并检查子字符串是否位于字符串中的某个位置(使用strncmp 函数),如果是,我想将值*p 更改为通过将其 ASCII 值减少 32 来获得一个大写字母。

为什么它不起作用?哪里错了?

【问题讨论】:

  • 请参阅toupper 库函数,并注意尝试修改字符串文字(您不显示输入)。
  • 使用strstr() 查找字符串。使用toupper()&lt;ctype.h&gt; 进行大小写转换。
  • 怎么不工作了?
  • for (p; p &lt; p + substringLength; p++) 现在你能描述一下p &lt; p + substringLength 会随着p 变化而从true 变为false 的情况吗?另一方面,不要使用幻数; 32 无论如何都有意义,请使用 islowertoupper 之类的函数。
  • 您在外部和内部嵌套循环中使用p 作为控制变量。使用不同的变量。

标签: c arrays string pointers substring


【解决方案1】:

内部循环的主要问题是 p 不能同时用作终止目标 (p + substringLength) 作为柜台。这就像说for (int i = 0; i &lt; i + 10; i++)i 会到达 i + 10 吗?

您可以尝试将p + substringLength 设置为变量len,然后使用该固定球门柱作为循环终止条件。

其次,使用toupper()进行字符转换。否则,空格和非字母字符也会被修改,导致意外行为。例如,空格会变成空终止字符,使字符串尾部成为孤立字符。

把它放在一起产生:

for (char *len = p + substringLength; p < len; p++)
{
    *p = toupper(*p);
}

最后,puts(p); 无法按预期工作。在函数结束时,p 用于遍历字符串,现在指向字符串的结尾,而不是开头。使用puts(str); 或简单地从调用范围打印以避免side effects

这是一个完整的例子:

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

void replaceSubstring(char *str, char *substr) {
    char *p = str;
    int substringLength = strlen(substr);

    while (*p)
    {
        if (strncmp(p, substr, substringLength) == 0)
        {
            for (char *len = p + substringLength; p < len; p++)
            {
                *p = toupper(*p);
            }
        }

        p++;
    }
}

int main(void) {
    char s[12] = "hello world";
    replaceSubstring(s, "llo wor");  
    printf("%s\n", s);
    replaceSubstring(s, "ll");  
    printf("%s\n", s);
    replaceSubstring(s, "h");  
    printf("%s\n", s);
    replaceSubstring(s, "hello worldz");  
    printf("%s\n", s);

    char t[28] = "i don't know how to do this";
    replaceSubstring(t, "do");  
    printf("%s\n", t);
    replaceSubstring(t, "'t know");  
    printf("%s\n", t);
    return 0;
}

输出:

heLLO WORld
heLLO WORld
HeLLO WORld
HeLLO WORld
i DOn't know how to DO this
i DOn'T KNOW how to DO this

Try it!

【讨论】:

  • 好吧,我明白我在那里做了什么,你是对的。但即使在将其更改为当前代码后,它仍然不会打印带有大写字母的新字符串,就好像那里的某些东西不起作用一样。
  • 你运行我的code example了吗?问题可能是你如何调用你没有指定的函数。贴一个完整的例子。您可能在调用者中声明了一个字符串常量,例如 char *s = "hello world";。此外,puts(p) 不会打印任何内容,因为p 已移动到字符串的末尾。使用puts(str) 或在调用范围内打印——你的函数should not be printing anything
  • 好吧,我只是把我的完整代码放在那里。我也把它改成了 puts(str) [我明白为什么],但是,程序并没有做我想做的事情,我不知道为什么..
  • 您更新的代码与您的原始解决方案或我提供的答案几乎没有关系。如果您想重构为使用strstr,这是一种全新的方法,与您的原始代码无法正常工作的原因没有任何关系。我建议删除所有这些,让你原来的问题可以回答(“为什么这个指针算法不起作用”,本质上),然后用minimal reproducible example打开一个新问题,询问为什么你的重构不起作用。
  • 您还没有发布主要内容,发布输出图片也无济于事,因此这不是 MCVE,并且会让您投反对票(以供将来参考)。说了这么多,我明白了问题所在。当您点击一个空格字符时,您减去 32,使其成为终止字符并孤立字符串的尾部。更新了我的帖子和链接代码。
【解决方案2】:

对于单字符串和单模式,你可以使用kmp。

https://www.geeksforgeeks.org/kmp-algorithm-for-pattern-searching/

对于一组字符串和单个模式,可能需要基于 fsm 的算法。

https://www.geeksforgeeks.org/finite-automata-algorithm-for-pattern-searching/

它们是非常经典的算法,并且已经讨论了很多。

【讨论】:

    猜你喜欢
    • 2021-01-06
    • 2018-12-29
    • 2012-01-03
    • 2012-02-17
    • 2012-11-18
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 2020-01-04
    相关资源
    最近更新 更多