繁体   English   中英

C:从字符串中删除重复的字母

[英]C : removing duplicated letters from string

我正在尝试从字符串中删除每个单词中的重复字母。(我还没有为大写和小写字母指定它)

输入:

Ii feel good    todday!!
thhis iss   fixed

Output:

I fel god today!
this is fixed

我主要调用这个 function,我必须在另一个 function 中使用结果。 这就是为什么我通过引用来称呼它。

int main(){
char string[100];
printf("Enter a string:");
gets(string);
dup_letters_rule(&string);
return 0;
}

void dup_letters_rule(char *str_[]){
char new_str_[100];
int i=0, j=0;
printf("Fixed duplicates:\n");
while(*str_[i]!='\0'){
    if(*str_[i]== *str_[i+1] && *str_[i+1]!='\0'){
        while(*str_[i]==*str_[i+1] && *str_[i+1]!='\0'){
            i++;
        }
        *str_[i]=new_str_[j];
        j++;
        i++;
    }
    else{
        *str_[i]=new_str_[j];
        j++;
        i++;
    }
}
new_str_[j]='\0';
puts(new_str_);
}
 

它的工作原理如下:

void dup_letters_rule(char *str_[]){
char *new_str_=*str_, *temp=*str_;
temp++;
printf("Fixed duplicates:\n");
while(*new_str_!='\0'){
    if(*new_str_== *temp && *temp!='\0'){
        while(*new_str_==*temp && *temp!='\0'){
            new_str_++;
            temp++;
        }
        putchar(*new_str_);
        new_str_++;
        temp++;
    }
    else{
         putchar(*new_str_);
         new_str_++;
         temp++;
    }
}
}

但是,我不能在另一个 function 中使用*str_字符串。

代码可以简化。

我们可以保留一个int值,它是之前看到的 char 并将其与当前char 进行比较,并且只有在它们不同时才“复制出来”。 (即我们只需要两个指针)。

我们还必须使用tolower因为IiI

尽管可以使用第二个/输出缓冲区,但 function 可以“就地”进行清理。 然后,调用者可以使用清理后的缓冲区。 这是我们通常想要做的。

如果调用者需要保留原始字符串,它可以将原始字符串保存到临时缓冲区并使用临时调用 function

我不得不重构你的代码。 我根据您的示例输入对其进行了测试。 注释如下:

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

void
dup_letters_rule(char *src)
{
    char *dst = src;
    int prev = -1;

    // rchr -- the "raw" char
    // lchr -- the result of tolower(rchr)
    // prev -- the previous value of lchr (starts with -1 to force output of
    //         first char)
    for (int rchr = *src++;  rchr != 0;  rchr = *src++) {
        // get lowercase char
        int lchr = tolower((unsigned char) rchr);

        // output if _not_ a dup
        if (lchr != prev)
            *dst++ = rchr;

        // remember this char for the next iteration
        prev = lchr;
    }

    *dst = 0;
}

int
main(void)
{
    char *cp;
    char buf[1000];

    while (1) {
        cp = fgets(buf,sizeof(buf),stdin);
        if (cp == NULL)
            break;

        // get rid of newline
        buf[strcspn(buf,"\n")] = 0;

        // eliminate dups
        dup_letters_rule(buf);

        // output the clean string
        printf("%s\n",buf);
    }

    return 0;
}

更新:

我可以在 dup_letters_rule function 中打印干净的字符串吗? - 仓鼠

当然,当然。 我们是程序员,所以我们可以做任何我们想做的事情;-)

函数有一个格言:做好件事

在许多实际(重新)用例中,我们希望简单/低级 function 进行打印。 那是常态。

但是,我们当然可以为 function 添加打印功能。 我们将printfmain移动到 function 本身。

为了两全其美,我们可以使用两个函数。 一个只做转换的人。 并且,第二个调用简单的 function 然后打印结果。

这里有一个微小的变化可以说明这一点。 我重命名了我的 function 并创建了dup_letters_rule嵌入了printf

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

void
dup_letters_rule_basic(char *src)
{
    char *dst = src;
    int prev = -1;

    // rchr -- the "raw" char
    // lchr -- the result of tolower(rchr)
    // prev -- the previous value of lchr (starts with -1 to force output of
    //         first char)
    for (int rchr = *src++;  rchr != 0;  rchr = *src++) {
        // get lowercase char
        int lchr = tolower((unsigned char) rchr);

        // output if _not_ a dup
        if (lchr != prev)
            *dst++ = rchr;

        // remember this char for the next iteration
        prev = lchr;
    }

    *dst = 0;
}

void
dup_letters_rule(char *buf)
{

    dup_letters_rule_basic(buf);

    // output the clean string
    printf("%s\n",buf);
}

int
main(void)
{
    char *cp;
    char buf[1000];

    while (1) {
        cp = fgets(buf,sizeof(buf),stdin);
        if (cp == NULL)
            break;

        // get rid of newline
        buf[strcspn(buf,"\n")] = 0;

        dup_letters_rule(buf);
    }

    return 0;
}

更新#2:

以及为什么不是char *dst = *src; 但是char *dst = src; - 仓鼠

这是基本的 C。 我们希望dst具有与src相同的值/内容。 就像我们做了:

int x = 23;
int y = x;

如果我们按照您的建议进行操作,编译器会标记该语句:

bad.c: In function ‘dup_letters_rule_basic’:
bad.c:8:14: warning: initialization of ‘char *’ from ‘char’ makes pointer from integer without a cast [-Wint-conversion]
  char *dst = *src;
              ^

执行char *dst = *src [正如您所建议的] 是以两种不同的方式使用*

执行char *dst表示dst被定义为指向char的指针。

在这里做*src [它是dst初始化器并且是一个表达式], *解引用操作符 它说“获取src指向的值(一个char )”。 不是我们想要的。

如果我们使用初始化器,这可能会更清楚。 我们使用定义(没有初始化器)并使用赋值语句设置dst的初始值:

char *dst;  // define a char pointer (has _no_ initial value)
dst = src;  // assign the value of dst from the value of src

赋值 [语句] 可以出现定义之后和for循环/语句之前的任何位置。 这是 function 主体的前几行:

char *dst;
int prev = -1;

dst = src;

要从字符串中删除重复的连续字符,请跟踪字符串中的 position,其中下一个字符与其前一个字符不同,并检查当前处理字符与前一个字符(忽略它们的差异case) 除非该字符是字符串的第一个字符,因为第一个字符之前没有任何字符。 如果当前处理字符与前一个字符相同,则移动到字符串中的下一个字符,如果它们不相同,则用当前处理字符覆盖跟踪的 position 处的字符,并将跟踪的 position 指针增加 1。

它的实现:

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

void remove_consecutive_dup_chars (char * pstr) {
    if (pstr == NULL) {
        printf ("Invalid input..\n");
        return;
    }

    /* Pointer to keep track of position where next character
     * to be write in order to remove consecutive duplicate character.
     */
    char * p = pstr;
    for (unsigned int i = 0; pstr[i] ; ++i) {
        if ((i) && (tolower (pstr[i]) == tolower (pstr[i - 1]))) {
            continue;
        }

        *p++ = pstr[i];
    }

    /* Add the null terminating character. 
     */
    *p = '\0';
}

int main (void) {
    char buf[256] = {'\0'};

    strcpy (buf, "Ii feel good    todday!!");
    remove_consecutive_dup_chars (buf);
    printf ("%s\n", buf);

    strcpy (buf, "thhis iss   fixed");
    remove_consecutive_dup_chars (buf);
    printf ("%s\n", buf);

    strcpy (buf, "");
    remove_consecutive_dup_chars (buf);
    printf ("%s\n", buf);

    strcpy (buf, "aaaaaa    zzzzzz");
    remove_consecutive_dup_chars (buf);
    printf ("%s\n", buf);
    
    return 0;
}

Output:

I fel god today!
this is fixed

a z

暂无
暂无

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

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