首页 > 解决方案 > 从字符数组中删除某些元素

问题描述

我有一个函数可以从给定的字符串中去除标点符号,并使其所有内容都小写:

void stripPunctuators(char *str)
{
  int i, j, len = strlen(str);


  for (i = 0; i < len; i++)
  {
     if (!isalpha(str[i]))
     {
       for (j = i; j < len; j++)
       {
         str[j] = str[j + 1];
       }
       len--;
     }

     str[i] = tolower(str[i]);
  }
}

但是由于某种原因,当我连续有两个非字母字符时它会遇到麻烦......这是我的主要功能:

 int main(void)
 {
   char str[50] = "Hello.";

   printf("Before strip: %s\n", str);
   stripPunctuators(str);
   printf("After strip: %s\n", str);

   char str2[50] = "Hello.!";

   printf("Before strip: %s\n", str2);
   stripPunctuators(str2);
   printf("After strip: %s\n", str2);

   return 0;
}

最后,这是我的输出:

Before strip: Hello.
After strip: hello
Before strip: Hello.!
After strip: hello!

谢谢你的帮助!

标签: cstring

解决方案


考虑一个短字符串可能会有所帮助,例如a!@b. 0..3由于您使用了循环,您的索引变量将遍历包含在内的值for。现在按照顺序:

0123     <- indexes
----
a!@b     starting point, index = 0
a!@b     index 0 was a, no shift, set index to 1
a@b      index 1 was !, shift, set index to 2 ***
a@b      index 2 was b, no shift, set index to 3, exit loop

从那里,您应该能够看到移动字符串的其余部分增加索引将导致下一个字符被跳过(请参阅***标记以了解出错的地方)。

您可以通过使用一个循环来解决此问题,在该循环中,当您进行轮班时,索引不会while增加(可能使用而不是for一个好主意)。这样,无增量的移位将使您重新检查相同的索引,即下一个字符(由于移位)。

但是,每次要删除字符时都对字符串余数进行完全移位是相当低效的,因为您很可能需要再次更改这些字符。

最好使用带有(伪代码)之类的源和目标指针:

set src and dst to address of first character
while character at src is not end-of-string:
    if character at src is not punctuation:
        set character at dst to be character at src
        increment dst
    increment src
set character at dst to be end-of-string

而且,如果你想在 C 中使用它,它会是:

void stripPunctuators(char *str) {
    char *src = str;
    char *dst = str;
    while (*src != '\0') {
        if (isalpha(*src)) {
            *dst = *src;  // or combine:
            dst++;        //   "*dst++ = *src"
        }
        src++;
    }
    *dst = '\0';
}

请注意,我isalpha在我的代码中使用它只是因为那是您在原始代码中使用的那个。由于这将剥离标点符号(例如数字),因此您可能需要重新检查它是否适合使用。该isalnum功能可能更合适,但也取决于您的用例。您可能还需要保留空格。

否则事情可能会变得非常混乱和难以阅读:-)


推荐阅读