如何通过C语言对英文文本内的单词出现次数进行统计?

问题遇到的现象和发生背景

如题。假如我输入一个英文资料文本和一个重点单词文本。两个文本中所有单词的单词间不包括空格和跨行,字母不区分大小写。 英文资料文本就是正常的英文小说段落。重点单词文本是仅由单词构成,单词间由逗号隔开。
程序统计重点单词文本中的单词在英文资料文本中出现的总次数,并按照出现次数由大到小进行单词排序。
按出现次数由大到小输出重点单词。输出格式无所谓。请问这种小程序代码怎么设计。我是一个英专生,自学的C语言。想设计一个高速复习的小程序。但是毫无头绪。

问题相关代码,请勿粘贴截图
运行结果及报错内容
我的解答思路和尝试过的方法
我想要达到的结果

请尽量使用基础的语法,我是一个初学者,高级语法并不能看得太懂

主要是字符串的分割和对比。
(1)先把终点单词提取出来,存到一个数组中(如果学过STL容器,也可以用list或者vector容器),并用一个数组记录重点单词出现的次数。
(2)读取英文资料文本(可以逐行读取,也可以一次性读取,处理方式类似),以逐行读取为例:
(a)读取一行文本,存入char数组中
(b)遍历char数组,用空格,逗号,点,问号,叹号分割字符串,把这一行的所有单词提取出来。
(c)每提取出一个单词,就判断该单词是否在重点单词数组中,如果在,就把对应的单词次数+1
(d)继续读取一行,继续a-c的步骤,直到文件读取完毕。


下面连接里有一个读取文件,并统计单词数量的代码,在它的基础上增加重点单词的统计就可以了。

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
 
#define MAXSTRLEN 1024
 
typedef struct node {
    int cnt;                       // 统计各个单词出现的次数 初始化为0
    struct node *next[40];           // 数字放在0-9,单词放在10-36 
}TrieTreeNode,* TrieTree;
 
TrieTree createTrieTreeNode();                        // 新建并初始化一个节点
int InsertTrieTreeNode(TrieTree *pT, char *str);  // 插入一个单词
int DeleteTrieTreeNode(TrieTree *pT, char *str);  // 删除一个单词
int SearchTrieTree(TrieTree T, char *str);      // 搜索Trie树
void TraverseTrieTree(TrieTree T);              // 遍历Trie树
void DestroyTrieTree(TrieTree *pT);               // 销毁Trie树
 
// 新建并初始化一个节点
TrieTree createTrieTreeNode() {
    TrieTreeNode *treeNode;

    treeNode = (TrieTreeNode*)malloc(sizeof(TrieTreeNode));    if (!treeNode) exit(0);
    memset(treeNode->next, 0x00, sizeof(treeNode->next)); //所有的next都赋值为0
    treeNode->cnt = 0;
    return treeNode;
}
 
// 插入一个单词
int InsertTrieTreeNode(TrieTree *pT, char *str) {
    int i, index;
    TrieTreeNode *tempNode = *pT;
    
    if(tempNode==NULL || str == NULL || str[0]=='\0') // Trie树带有一头结点
        return 0;
    
    // 遍历字符串,找到Trie中的位置
    for(i=0; i<strlen(str) ;i++) {
        if (str[i]>='0' && str[i]<='9') //数字
            index = str[i] - '0'; //下标放在[0,9]
        else if (str[i]>='a' && str[i]<='z') //字母 
            index = str[i] - 'a' + 10; //下标放在[10,36]
        else {
            printf("单词错误,有别的类型字符\n");
            return 0;
        }
        
        // 往下走
        if (tempNode->next[index] == NULL) { //还没有这个结点
            tempNode->next[index] = createTrieTreeNode();
        }
        tempNode = tempNode->next[index]; //往下走
    }
    // 计数
    tempNode->cnt = tempNode->cnt + 1;

    return 0;
}
 
 
/*
 * 搜索Trie树
 * 存在返回个数
 * 不存在返回0
 */
int SearchTrieTree(TrieTree T, char *str) {
    int i, index; 
    TrieTreeNode *tempNode = T;

    if(tempNode==NULL || str == NULL)
        return 0;
    
    //搜索
    for(i=0; i<strlen(str); i++) {
        if (str[i]>='0' && str[i]<='9') //数字
            index = str[i] - '0'; //下标放在[0,9]
        else if (str[i]>='a' && str[i]<='z') //字母 
            index = str[i] - 'a' + 10; //下标放在[10,36]
        else {
            printf("单词错误,有别的类型字符\n");
            return 0;
        }

        if(tempNode->next[index] == NULL) { //走不下去了
            return 0; //没找到
        }
        tempNode  = tempNode->next[index];
    }
    
    return tempNode->cnt;
}  
 
/*
 * 删除单词
 * 不存在返回0
 * 存在返回删除后的个数
 */
int DeleteTrieTreeNode(TrieTree *pT, char *str) {
    int i, index; 
    TrieTreeNode *tempNode = *pT;
     
    if(tempNode==NULL || str == NULL) 
        return 0;
    
    for(i=0; i<strlen(str); i++) {
        if (str[i]>='0' && str[i]<='9') //数字
            index = str[i] - '0'; //下标放在[0,9]
        else if (str[i]>='a' && str[i]<='z') //字母 
            index = str[i] - 'a' + 10; //下标放在[10,36]
        else {
            printf("单词错误,有别的类型字符\n");
            return 0;
        }

        if(tempNode->next[index] == NULL) {
            return 0;
        }
        tempNode  = tempNode->next[index];
    }
    tempNode->cnt = tempNode->cnt-1;
    return tempNode->cnt;
}
 
// 遍历Trie树,使用静态变量,递归时可以记录之前一层上的字符
void TraverseTrieTree(TrieTree T) {
    int i;
    static char word[MAXSTRLEN+1] = {'\0'};
    static int len=0;
    
    if(T==NULL) 
        return;

    for(i=0; i<37; i++) {
        if (T->next[i]==NULL) {
            continue;
        }
        // 赋值
        if (i>=0 && i<=9) { //数字
            word[len++] = i + '0';
        } else { //字母
            word[len++] = i - 10 + 'a';
        }
        // 如果这个字符串存在,输出
        if(T->next[i]->cnt > 0) {
            word[len] = '\0';
            printf("%-20s %-8d\n", word, T->next[i]->cnt);
        }
        // 遍历下一个
        TraverseTrieTree(T->next[i]);
        len--;
    }
}
 
/*销毁Trie树*/
void DestroyTrieTree(TrieTree *pT) {
    int i;
    
    if((*pT)==NULL) 
        return;
    
    for(i=0; i<40; i++) {
        if((*pT)->next[i] != NULL) {
            DestroyTrieTree(&(*pT)->next[i]);
        }
    }
    
    free(*pT); // 子节点全部删除
    *pT = NULL;
}            

int main() {
    char word[1024+1] = {'\0'}; //存放读到的单词
    char c;
    int len;
    TrieTree T = NULL;
    FILE *fp;

    T =  createTrieTreeNode(); //创建Trie树

    // 读入文件
    fp = fopen("2013-8.txt", "r");
    len = 0;
    while ( fscanf(fp, "%c", &c)!=EOF ) {
        if ( c>='0' && c<='9' ) { //数字
            word[len++] = c;
        } else if ( c>='a' && c<='z' ) { //小写字母
            word[len++] = c;
        } else if ( c>='A' && c<='Z') { //大写字母
            word[len++] = c - 'A' + 'a'; //转成小写,考虑
        } else { //其他字符
            if (len==0) { //前面没有单词
                continue; //继续
            } else { //前面有单词
                word[len] = '\0'; //附上结束串
                //printf("- %s\n", word); //debug打印读取的字符串
                InsertTrieTreeNode(&T, word); //插入Trie树
            }
            len =0;
        }
    }
    fclose(fp);

    // 输出全部单词的次数
    TraverseTrieTree(T);
    // 销毁
    DestroyTrieTree(&T);
    
    return 0;
}  

可以参考一下,再加入一个数组存储你的重点单词,只统计重点单词里面的数据

如果是C++,相对比较容易,C的话,初学就算了。
用C++的hashmap存重点单词本,每个单词转小写。
结构是key:单词,value:个数,初始为0。
用file流顺序输入string,和hashmap中的key比较,相同则 value+=1。
完成所有输入后,进行forrange迭代,将所有键值对颠倒存入vector<pair<int,string>>,按大于逻辑sort一下。
forrange迭代输出即可。

C++有个问题,没有split,这个的实现要看具体文本的格式,并不容易。


#include<stdio.h>
main(){
char a[100],word[30];
int i=0,j,na=0,nw=0,count=0,sum=0;

while((a[i] = getchar()) != '\n'){//这里括号必须加,不然赋值优先级低于逻辑符号,数组里存的全是‘\0’
na++;
i++;
}
i=0;
rewind(stdin);
while((word[i] = getchar()) != '\n'){
nw++;
i++;
}
for (i = 0; i < na; i++)
{   count = 0;
    if(a[i] == word[0]){//第一个字符匹配上了才继续匹配
        for(j=0;j<nw;j++){
            if(a[i+j] == word[j]){
                count++;
            }
        }
        if(count == nw)sum++;//匹配数=word的字符数那么匹配成功
    }
}
printf("%d",sum);

}

类似聊天软件中的敏感词查找,可以使用trie tree

https://www.91dengdeng.cn/2020/07/03/%E6%95%8F%E6%84%9F%E8%AF%8D%E8%BF%87%E6%BB%A4/