繁体   English   中英

从C中的字符串中删除子字符串

[英]Removing a substring from a string in C

我已经有从C中的字符串(单词)中删除子字符串的代码,但我不理解。 有人可以向我解释吗? 它不使用标准库中的函数。 我试图自己分析它,但是某些部分我还是不明白-我将它们放在注释中。 我只需要弄清楚这一切是如何工作的。

谢谢!

#include <stdio.h>
#include <stdlib.h>
void remove(char *s1, char *s2);

int main()
{
   char s1[101], s2[101];
   printf("First word: ");
   scanf("%s", s1);
   printf("Second word: ");
   scanf("%s", s2);
   remove(s1, s2);
   printf("The first word after removing is '%s'.", s1);

   return 0;
}
void remove(char *s1, char *s2)
{
   int i = 0, j, k;
   while (s1[i])       // ITERATES THROUGH THE FIRST STRING s1?
   {
       for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // WHAT DOES THIS LINE DO?
          if (!s2[j])           // IF WE'RE AT THE END OF STRING s2? 
             {
                 for (k = i; s1[k + j]; k++)   //WHAT DOES THIS ENTIRE BLOCK DO?
                    s1[k] = s1[k + j];
                    s1[k] = 0;
              }
          else
              i++;    // ???
    }
}

这里的功能主要工作是这样的:

-跳过两个字符串之间的公共部分,并为第一个字符串分配新的字符串。

while (s1[i])       // Yes It ITERATES THROUGH THE FIRST STRING s1
       {
           for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // Here it skips the part which is 
//similar in both

由于此循环仅增加公共部分的索引,因此将跳过s1中的数据存储。

if (!s2[j])           // IF WE'RE AT THE END OF STRING s2
{
 for (k = i; s1[k + j]; k++)   //Here it is re assigning the non common part.
 s1[k] = s1[k + j];
 s1[k] = 0;
}
else
 i++;    // it is req. if both have more values.
}

第一个while (s1[i])遍历s1。 是的,你是对的。

for (j = 0; s2[j] && s2[j] == s1[i + j]; j++); 

上面的for循环从s1 [i]开始检查s1中是否存在子字符串s2。 如果匹配,则完全迭代s2。 如果不是,则在for循环的末尾,s2 [j]将不是空字符。 示例:如果s1 = ITERATE且s2 = RAT,则仅当i = 3时循环才会完全执行。
因此, if (!s2[j])成立,则意味着我们找到了一个子字符串,而i是s1中子字符串的起点。

         for (k = i; s1[k + j]; k++)   //WHAT DOES THIS ENTIRE BLOCK DO?
            s1[k] = s1[k + j];
            s1[k] = 0;

abov块删除子字符串。 因此,对于ITERATE和RAT示例,这是通过在存在R和A的位置复制E和null char来完成的。 for循环可实现此目的。 如果for循环后s2 [j]不为null,则i递增以检查是否从s1的下一个位置开始。

这是注释中浓缩的功能的一种方法

void remove(char *s1, char *s2)
{
   int i = 0, j, k;
   while (s1[i])       // Iterates through s1 (until it finds a zero)
   {
       for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // Iterates through s2 while both it is NOT the end of the string s2 and each character of s2 coincides with s1 (if s2 == s1, j points to the end of s2 => zero)
          if (!s2[j])           // If j point to the end of s2 => We've found the coincidence
             {
                 for (k = i; s1[k + j]; k++)   //Remove the coincident substring
                    s1[k] = s1[k + j];
                    s1[k] = 0;
              }
          else
              i++;    // There is no coincidence so we continue to the next character of s1
    }
}

注意:我还注意到,由于它迭代到s1范围之外,因此很容易解释。

让我们分解一下。 你有

while (s1[i])
{
    // Code
}

这遍历s1 到达字符串的末尾后,您就有\\0 ,这是空终止符。 在条件中求值时,它将求值为0 这可能是更好的使用for这里。

然后你有

for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);

这除了增加j什么都没有。 应当注意,该表达式没有花括号,并且以分号结尾,因此不应在循环体内执行之后的代码。 如果确实具有正确的括号,则它将在以下if/else循环,而s2不为null且s2[j] == s1[i+j] 除了s2的字符被s1 i偏移之外, i对第二部分实际上没有任何解释。 该部分可能会得到改进,以消除不必要的迭代。

然后有

if (!s2[j])
{
}
else
{
}

这将检查以确保s2的位置有效,并执行删除字符串的操作,否则将i递增。 s2不再适合s1的其余部分时,可以通过返回else来改善它。

for (k = i; s1[k + j]; k++)
    s1[k] = s1[k + j];
    s1[k] = 0;

这是另一个有点奇怪的循环,因为由于没有花括号,因此将在循环外部设置s1[k] = 0 这里发生的是,通过删除s2并将k+j处的字符向下移动到k来压缩字符串。 在循环的末尾, s1[k] = 0结束以正确结束的空终止符中的字符串。

如果您想更深入地了解,可能值得尝试编写自己的代码来做相同的事情,然后再进行比较。 我发现,这通常比阅读大量测试更有帮助。

暂无
暂无

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

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