【问题标题】:How do I count words with apostrophe character如何计算带有撇号字符的单词
【发布时间】:2020-10-24 11:35:20
【问题描述】:

我正在开发一个 C 语言的字数统计程序。 一切正常,但是当我谈到撇号字符控制时,我有点困惑。 问题是,我的程序无法识别这两个示例之间的区别:Ive 和 Jem 的。 如果单词中有撇号字符,我的程序会将其计为两个单词。应该将第一个示例计为 2 个单词,将第二个示例计为一个单词。 请问您有什么问题吗?

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

int main(void) {

    string inputstr;
    int letters = 0;
    int words = 0;
    int sentences = 0;
    char c;
    float index;

    inputstr = get_string("Text:");

    for (int i = 0; i <= strlen(inputstr); i++)
    {
        c = inputstr[i];

        if (isalnum(c))//count letters
        {
            letters++;

        }
        else if (isspace(c) || c == '\0' || c == 39)//count words
        {
            words++;

        }
        else if (c == '.' || c == '?' || c == '!')//count sentences
        {
            sentences++;

        }

    }//end of for loop

    return 0;
}// end of main

【问题讨论】:

  • 准确地做起来相当棘手。您可能不得不大幅增加算法的复杂性。
  • 如果不真正了解单词以及撇号符号的省略方式,您想要实现的目标是不可能的。您的程序如何知道“Jem's”是指“Jem 是”还是“属于 Jem”?你的程序甚至知道这些单词是英文的吗?
  • 您需要一个相当复杂的有限状态机 + 一些启发式方法。 (或撇号后允许的片段的查找表)另一种方法是始终将构造视为由标记器生成的三个单独的标记,并且可能在第二个中合并标记(语义) 步骤。
  • 显示您的代码。
  • 别忘了Smiths'只有一个字。

标签: c count cs50 word


【解决方案1】:

我制作了一个快速程序,可以为您提供一些想法。请注意,我很快就将它破解了。它写得不是很好,可能包含错误。但这足以表明想法。

基本思想是在每个单词中查找撇号。如果找到了,请查看撇号后面的内容并使用它来决定是否应该增加 count

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>

char *next(char *str, char *delims) {
    size_t len = strlen(delims);
    while(*str) {
        for(size_t i=0; i<len; i++)
            if(*str == delims[i]) return str+1;
        str++;
    }
    return NULL;
}

int main(void)
{
    char *str = "Now I've broken Johan's computer";
    char *delims = "., ";
    char *c = str;
    char *n;
    size_t count = 0;
    while(1) {
        n = next(c, delims);
        count++;
        ptrdiff_t d;
        if(!n) d = strlen(c);
        else d = n-c;
        char *word = malloc(d + 1);
        strncpy(word, c, d);
        printf("%zu %s\n", count, word);
        char *apo = next(word, "'");
        if(apo) {
            char *t = next(apo, delims);
            if(!t) d = strlen(apo);
            else d = t-apo;
            char *after = malloc(d+1);
            strncpy(after, apo, d-1);
            if(strcmp(after, "ve") == 0) count++;
            free(after);
        }
        free(word);
        if(!n) break;
        c = n;
    }
    printf("Count: %zu\n", count);
}

输出:

$ ./a.out 
1 Now 
2 I've 
4 broken 
5 Johan's 
6 computer
Count: 6

【讨论】:

  • 谢谢先生。这很有帮助。我感激你。检查撇号后面的字符是我的重点。
【解决方案2】:

最小有限状态机:


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

        /* Tokenise, recognising word's AS a single token
        ** But NOT we're !111!!!
        */
int fetch_word(char *str, size_t len)
{
size_t pos;
int state;

state =0;
for (pos = 0; pos < len; pos++) {
        int ch;
        ch = str[pos];
        switch (state) {
        case 0: /* initial or whitespace */
                if (strspn(str+pos, " \t\r\n\v\f")) continue;
                if (pos) return -pos;
                if (isalpha(ch)) {state = 1; continue; }
                state = 4; continue;
        case 1: /* word */
                if (pos >= 2 && ch == '\'') {state = 2; continue; }
                if (isalpha(ch)) {continue; }
                return pos;
        case 2: /* word + apos */
                if (isalpha(ch)) {state = 3; continue; }
                return pos -1;
        case 3: /* word+ apos + letter */
                if (strspn(str+pos, " \t\r\n\v\f")) return pos;
                return pos -2;
        case 4: /* other */
                if (isalpha(ch)) return -pos;
                if (!strspn(str+pos, " \t\r\n\v\f")) continue;
                return -pos;
                break;
                }
        }
/* not reached (well:seldom) */
return (state==1) ? pos : -pos;
}

int main(void)
{
char buff[200];
int ret;
size_t pos,len,count;

count=0;
while ( fgets(buff, sizeof buff, stdin) ) {
        len = strlen(buff);
        for(pos= 0; pos < len ; pos += ret) {
                ret = fetch_word(buff+pos, len-pos);
                if (!ret) break;
                if (ret < 0) { ret = -ret; continue; }
                printf("%zu+%d:%.*s\n" , pos, ret, ret, buff+pos);
                count++;
                }
        }
printf(" Count=%zu\n" , count);
return 0;
}

为其提供自己的源文件:


1+7:include
10+5:stdio
16+1:h
1+7:include
10+6:string
17+1:h
1+7:include
10+5:ctype
16+1:h
4+8:Tokenise
14+11:recognising
26+6:word's
33+2:AS
36+1:a
38+6:single
45+5:token
4+3:But
8+3:NOT
12+2:we
15+2:re
0+3:int
4+5:fetch

休息一下

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 2023-03-26
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多