计算C中字符串中n长度字的出现次数

时间:2016-04-24 05:58:39

标签: c

新来的,我正在寻求帮助。试着自学C并在网上找到一些作业。 (https://www.cs.cf.ac.uk/Dave/C/node7.html)基本上只是试图通过只找到一个n长度的单词而不是倍数来生成该作业的一部分(练习12337)。我的程序现在计算单词的总数,但我不知道如何超越这一点开始根据它们的长度挑出单词。

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

int words(const char lne[ ]);

int main()
{
    char lne[60], name[25]=""; 
    FILE *fp;

    printf("Enter name of the input file: ");
    scanf("%s", &name);

    if ((fp = fopen(name, "r")) == NULL)
    {
        printf("File cannot be opened!");
    }

    else
    {
        int cntf=-1, cntw=-1;
        while (fgets(lne, sizeof lne, fp))
        cntf += words(lne);
        //cntw += letter(lne);
        printf("\nThe most frequent word length is %d", cntf );
        printf("\nThe message includes %d words of that length", cntf);


        fclose(fp);
    }

    return 0;
}

int words(const char lne[])
{
    int i, count=0;
    for (i=0; i<strlen(lne); i++)
    {
        if (lne[i] == ' '||lne[i] == '\t'||lne[i] == '\n')
            count++;
    }
    return count;
}

1 个答案:

答案 0 :(得分:0)

当测量范围内任何事件的频率(字长,字符出现等)时,一种非常简单的方法是声明一个数组,该数组至少包含该范围内的最大元素数(例如,如果你正在计算a-z的出现次数,您需要至少26个元素的数组。 (对于单词长度,您需要一个至少为27的数组 - 未删节字典中最长单词的长度)。如果范围不确定,您可以随时添加一些额外的元素以确保覆盖范围。

必须将数组初始化为0。然后,对于每次出现,继续a-z示例,每次遇到a时,您都会增加与a相关联的索引(例如0,{{1} },b=1)等等。因此,当遇到c=2时,您的数组名称为a时,您将增加

charfreq

在您阅读所有字符并增加相关索引后,charfreq[0]++; 中的值是charfreq[0]的数量,a charfreq[1]的数量}&#39; s,等等。

您也可以使用这种精确的方法来收集字长的频率。在找到长度的频率之前,您当然必须找到单词的数量。虽然您可以通过计算每行的空格分隔符并添加b来手动查找单词数,但这并不能让您获得每个单词的长度(当您计算空格时,您可以沿着字符串向下走2个指针在每个单词之后终止/恢复并获取指针差异),但C库有1来帮助您为该行标记。

当您对行进行标记时(无论您如何操作),您只需要获取每个标记(字)的长度并更新频率数组 - 您就完成了。 strtok函数可以在words的帮助下编写如下(注意strtok修改原始字符串,因此如果必须保留原文,则需要一份副本)

strtok

将这些部分放在一起,注意文件名通常作为参数传递,您可以执行类似以下操作来读取/处理文件中的单词(或默认情况下来自int words (const char *buf, const char *delims, int *freq) { char tmp[MAXC] = ""; /* temp array to hold buf as */ char *p; /* strtok modifies original */ int cnt = 0; strncpy (tmp, buf, sizeof tmp); /* copy buf to tmp & tokenize */ for (p = strtok (tmp,delims); p; p = strtok (NULL, delims)) { cnt++; freq[strlen(p)]++; } return cnt; } ):

stdin

示例输入文件

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

enum { MAXF = 32, MAXC = 256 };

int words (const char *buf, const char *delims, int *freq);

int main (int argc, char **argv) {

    char buf[MAXC] = "";
    char *delims = " ,.\t\n";      /* delimiters for strtok */
    int cntw = 0, i, midx = 0, mfreq = 0;
    int freq[MAXF] = {0};
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file is open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, sizeof buf, fp))     /* read each line */
        cntw += words (buf, delims, freq);  /* call words     */

    i = MAXF;
    while (i--)          /* find longest most frequent length */
        if (freq[i] > mfreq) {   /* in mfreq, which occurs at */
            mfreq = freq[i];     /* midx - most frequent idx  */
            midx = i;
        }

    /* output results */
    printf (" \n There are '%d' words in the file.\n", cntw);
    printf (" The most frequent word length is '%d'\n", midx);
    printf (" The message includes '%d' words of that length.\n\n", 
            mfreq);

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

int words (const char *buf, const char *delims, int *freq)
{
    char tmp[MAXC] = "";    /* temp array to hold buf as */
    char *p;                /* strtok modifies original  */
    int cnt = 0;

    strncpy (tmp, buf, sizeof tmp); /* copy buf to tmp & tokenize */
    for (p = strtok (tmp,delims); p; p = strtok (NULL, delims)) {
        cnt++;
        freq[strlen(p)]++;
    }

    return cnt;
}

示例使用/输出

$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

使用$ ./bin/wordsmfreq <../dat/captnjack.txt There are '16' words in the file. The most frequent word length is '4' The message includes '4' words of that length. 代替strcspn

图书馆中还有另一个值得的功能,strtok。它将扫描字符串以查找未包含在分隔符中的事件。它返回不包含strcspn列表中任何拒绝字符的初始段的长度。你可以使用该函数在delims上重复调用,同时将指针推到tmp以完成tmp所做的事情。 (无需拨打strtok

查看示例,如果您有任何问题,请告诉我。