【问题标题】:Remove duplicate words from the sentence in C从C中的句子中删除重复的单词
【发布时间】:2013-08-14 05:08:36
【问题描述】:

我需要编写一个函数来从字符串中删除所有重复的子字符串,下面的函数做得比工作但不太正确。

输入:这是第2课的简单测试退出第2课

输出:这个针对第 2 课退出的简单测试

如您所见,函数 remove "is" 从句子中但不正确。

void RemoveDuplicates(char text[], size_t text_size, char** output)
{
    char *element;
    /* Allocate size for output. */
    *output = (char*) malloc(text_size);
    *output[0] = '\0';

    /* Split string into tokens */
    element = strtok(text, " ");
    if (element != NULL)
        strcpy(*output, element);

    while( (element = strtok(NULL, " ")) != NULL ) {
        /* Is the element already in the result string? */
        if (strstr(*output, element) == NULL) {
            strcat(*output, " " );
            strcat(*output, element );
        }
    }
}

更新的代码版本 (@Rohan)

输入:这是一个简单的测试,对于第 2 课退出很简单

输出:这是一个简单的测试,对于第 2 课退出很简单

void RemoveDuplicates(char text[], size_t text_size, char** output)
{
    char *temp = NULL;
    char *element;
    /* Allocate size for output. */
    *output = (char*) malloc(text_size);
    *output[0] = '\0';

    /* Split string into tokens */
    element = strtok(text, " ");
    if (element != NULL)
        strcpy(*output, element);

    while( (element = strtok(NULL, " ")) != NULL ) {
        /* Is the element already in the result string? */
        temp = strstr(*output, element);
        /* check for space before/after it or '\0' after it. */
        if (temp == NULL || temp[-1] == ' ' || temp[strlen(element)] == ' ' || temp[strlen(element)] == '\0'  ) {

            strcat(*output, " " );
            strcat(*output, element );
        }
    }
}

【问题讨论】:

    标签: c string algorithm char


    【解决方案1】:

    您需要检查element 中的单词而不是纯字符串。

    你得到的是,在你的输入字符串中有 2 个"is" 一个是"This" 的一部分,而另一个是实际单词"is"

     This is a simple test for lesson2 Quit lesson2
     --^ -^  
    

    strstr() 找到两个字符串,并删除第二个"is"。但是您只需要找到重复的单词。

    您可以通过检查找到的单词前后的空格 ' ' 来做到这一点。如果它的最后一个字在最后检查'\0'

    尝试将您的 while 循环更新为:

    char temp[512] = { 0 }; //use sufficient array
    while( (element = strtok(NULL, " ")) != NULL ) {
            /* Is the element already in the result string? */
            //create word
            sprintf(temp, " %s ", element);
            if(strstr(*output, temp) == NULL) {
                strcat(*output, " " );
                strcat(*output, element );
            }
        }
    

    【讨论】:

    • (-1) 您的替代方法可能是正确的,但您的代码相对于他的初始代码是错误的。看看他对output的定义。
    • @JacobPollack,这不是真正的问题!
    • 我取消了我的反对票,因为我无法证明它的合理性。但我不明白为什么你所说的很重要,你能在你的回答中进一步详细说明吗?
    • @JacobPollack,添加了一些解释。
    • (+1) @Rohan,根本没有意识到这一点。很棒的观察。
    【解决方案2】:

    免责声明: 这不会修复您的算法,请参阅@Rohans 回答您的算法中的修复问题。


    要修复您的代码,请执行以下操作:

    *output = (char*) malloc(text_size);
    

    ...应该是:

    char *output = malloc(text_size);
    

    ...并改变:

    *output[0] = '\0';
    

    ...成为:

    output[ 0 ] = '\0';
    

    ...不要强制分配内存块。您可以阅读更多关于此here 的信息。注意output[ 0 ] 隐含*( output + 0 )

    接下来,改变:

    strcpy(*output, element);
    

    ...到:

    strcpy(output, element);
    

    ...然后改变:

    if (strstr(*output, element) == NULL) {
      strcat(*output, " " );
      strcat(*output, element );
    }
    

    ...到:

    if (strstr(output, element) == NULL) {
      strcat(output, " " );
      strcat(output, element );
    }
    

    ... 请注意 output 已经是一个指针,使用 * 就像您取消引用返回字符的指针一样。 strstrstrcpy 要求 dest 是一个指向字符数组的指针,一个字符。

    【讨论】:

    【解决方案3】:

    你可以试试这样的方法

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char test_text[] = "This is a is is simple test simple for lesson2 Quit";
    
    int main(int argc, char* argv[])
    {
      const int maxTokens = 200; // lets assume there is max 200 tokens in a sentence
      char* array[maxTokens];    // pointers to strings
      int unique_tokens = 0;     // number of unique tokens found in string
    
      // first tokenize the string and put it into a structure that is a bit more flexible
      char* element = strtok(test_text," ");
      for (; element != NULL; element = strtok(NULL, " "))
      {
         int foundToken = 0;
         int i;
         // do we have it from before?
         for (i = 0; i < unique_tokens && !foundToken; ++i)
         {
           if ( !strcmp(element, array[i]) )
           {
             foundToken = 1;
           }
         }
    
         // new token, add
         if ( !foundToken )
         {
           array[unique_tokens++] = (char*)strdup(element); // this allocates space for the element and copies it
         }
      }
    
      // now recreate the result without the duplicates.
    
      char result[256] = {0};
      int i;
      for (i = 0; i < unique_tokens; ++i)
      {
        strcat(result,array[i]);
        if ( i < unique_tokens - 1 )
        {
          strcat(result," ");
        }
      }
    
      puts( result );
    
      return 0;
    }
    

    【讨论】:

    • 可能这个for (i = 0; i &lt; unique_tokens &amp;&amp; !found; ++i) 应该包含foundToken 而不是found
    • @G.Samaras 是的,您当然是对的,已解决,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    相关资源
    最近更新 更多