在C字符串中删除所有字符出现的位置 - 需要示例

9
输入字符串:"我感觉不舒服","我们需要去看医生","需要多久时间?"
输出字符串:我感觉不舒服 我们需要去看医生 需要多久时间? 需要清除所有出现的字符"。我可以想到以下方法:
  1. 使用strchr()函数找到第一个"的出现。
  2. 将字符串中的所有字符向左移动一位。
重复步骤1和2,直到strchr()返回空指针。
我认为这种方法非常低效。我需要知道是否有其他方法来解决这个问题?伪代码或实际代码都可以。

给定索引处的字符;https://dev59.com/UW035IYBdhLWcg3wYO51 - Ciro Santilli OurBigBook.com
4个回答

16
for (s=d=str;*d=*s;d+=(*s++!='"'));

1
@ephemient:是的,我想让它可读性和教学性更强。;-) - R.. GitHub STOP HELPING ICE
@R - 你能解释一下这个是怎么工作的吗?我知道在C语言中,char*是以'\0'结尾的字符数组。你在for循环中没有删除任何字符'"'。另外,d+=(*s++!='"')的行为是什么?下面有一个很好的解释,由Leftium提供,但他没有解释当他第二行的if条件失败时该怎么做。 - Eternal Learner
@Eternal Learner:即使源指向",进行赋值也是安全的,因为目标指针没有被更新,在下一次循环中将被覆盖。 s ++ 后递增s* s ++ 解除引用后递增s* s ++!= '"' 将解除引用后递增的s"进行比较,并产生10;如果解除引用后递增的s不是",则 d + =(* s ++!= '"') 使d增加一。非常简单。 - ephemient
@asveikau:我关于保持可读性的评论有一半是玩笑,但我对在算术中使用==没有问题。我经常做类似(x==y)<<FLAG_BITy&-(x<y)的事情。 - R.. GitHub STOP HELPING ICE
我刚刚使用这个方法去除UUID中的连字符。完美,只是我不得不在条件周围添加一些括号来满足gcc的要求。我的代码是for (s=d=str;(*d=*s);d+=(*s++!='-')); 我必须解决的编译器错误是:error: suggest parentheses around assignment used as truth value [-Werror=parentheses] - starfry
显示剩余2条评论

9
您可以通过访问字符串的每个字符来实现此操作。您基本上将字符串复制到自身,跳过“字符”:

伪代码:

  1. 从两个指针开始:源和目标。它们都指向字符串的第一个字符。
  2. 如果 *SOURCE == NULL,则设置 *DESTINATION = NULL。停止。
  3. 如果 *SOURCE != ",则设置 *DESTINATION = *SOURCE,并递增 DESTINATION。
  4. 递增 SOURCE。转到步骤 2。

代码:

// assume input is a char* with "I am unwell\" \"We need to go..."

char *src, *dest;

src = dest = input;    // both pointers point to the first char of input
while(*src != '\0')    // exit loop when null terminator reached
{
    if (*src != '\"')  // if source is not a " char
    {
        *dest = *src;  // copy the char at source to destination
        dest++;        // increment destination pointer
    }
    src++;             // increment source pointer
}
*dest = '\0';          // terminate string with null terminator              

// input now contains "I am unwell We need to go..."

更新: 修复了代码中的一些错误


实际上你的代码有一个错误。按照现在的写法,它会从第一个字节开始读取并写入第二个字节,因此会覆盖自己的输入。你需要在存储后才增加“destination”的值,而不是之前,并且完全放弃对“destination”的最后一次增量操作。 - R.. GitHub STOP HELPING ICE
而且 destination = NULL; // terminate string with NULL 代码与注释不匹配。使用 *destination = '\0'; // terminate string with NUL 更为合理。此外,注意 "..." 是一个 const char *,而不是 char * — 根据 C 规范,对其进行写入操作是未定义的行为。 - ephemient
1
根据C规范,字符串字面量是不可修改的“char[]”(6.4.5 /#6),而不是“char *”,更不用说“const char ”。gcc的选项“-Wwrite-strings”使文字字符串成为类型为“const char []”,因此使gcc编译几乎是C的语言。 - pmg
你仍然在使用 NULL,而应该使用 0(或者如果你坚持的话,使用 '\0')。NULL 是一个指针常量,而不是空字符。 - R.. GitHub STOP HELPING ICE

0

如果你的字符串不是很大,显而易见的答案就是有一个单独的字符串。 一个循环直到你得到 \0(字符串结束符) 有一个循环(给你 O(n))和一个比较来检查当前字符串位置是否是所需字符(再次 O(n))

总之:


  s1 = original array
  s2 = new array to store the final result
  c = character in question.  
  current_pointer = 0 
  new_pointer =0 
  while(s1[current_pointer] != '\0') {
   ele = s1[current_pointer] ;

   if( ele != c)  { 
    s2[new_pointer++] = ele
   }
    current_pointer++
  }

请注意,此方法仅适用于字符串大小较小的情况。随着字符串大小的增加,我们需要采用更好的方法。
希望这可以帮助到您。

0

不要将“原地”移动字符以覆盖被删除的字符,而是创建一个新字符串。

这通过仅复制每个有效字符一次来最小化复制的字符数。使用原始方法,靠近字符串末尾的字符会被复制n次,其中n是其前面的无效字符数。


这是低效的。我的算法是原地算法或非原地算法(我写的是原地算法,但两种都可以),每个字符只复制一次。 - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接