2

我需要编写代码来读取文本文件并输出单词数、不同单词数和 C 中最常见的单词。

我已经完成了输出单词数量的代码,但是我不知道如何找到不同单词的数量或最常见的单词。我知道我应该使用 strcmp,但我不知道这样做。任何帮助将不胜感激。这是我到目前为止所拥有的。

int main(int argc, char *argv[])
{
    int number=0;
    char temp[25000][50];
    char word[25000][50];
    char *word2[25000][50];
    int wordCount=0;
    int distinctCount=0;
    FILE *fp;

    //reads file!
    fp = fopen("COEN12_LAB1.txt", "r");

    if(fp == NULL)
    {
        printf("File Missing!\n");
        return 0;
    }

    //counts words in file!
    while(fscanf(fp,"%s", word) == 1)
        wordCount++;

    printf("Total number of words: %d\n", wordCount);
    fclose(fp);`
}
4

4 回答 4

1

首先,您可能需要实现允许您有效保留不同单词的结构。哈希表是可能的之一(也许是最好的)。

以下是在 C 上实现和使用哈希的示例:

你也可以看看这个问题:Porting std::map to C?

于 2013-09-27T23:01:20.737 回答
0

[编辑]
1. 用 calloc 替换 malloc(将内存初始化为 0)
2. 替换 qsort 中的第二个参数
3. 程序现在可以处理更广泛的文件(更多单词,更多分隔符)

这并不漂亮,可能需要一些小的调试,但它会让你开始计数,不同的和最常用的单词的数量:

#include <ansi_c.h>
#include <stdio.h>

#define FILENAME "c:\\dev\\play\\test3.txt" //put your own path here
#define DELIM "- .,:;//_*&\n"

int longestWord(char *file, int *cnt);
void allocMemory(int numStrings, int max);
void freeMemory(int numStrings);

static int sortstring( const void *str1, const void *str2 );

char **strings;

int main()
{
    int wc, longest, cnt, distinct, i, mostFreq, mostFreqKeep=0;
    char line[260];
    char *buf=0;
    FILE *fp;

    longest = longestWord(FILENAME, &wc);

    char wordKeep[longest];
    allocMemory(wc, longest);

    //read file into string arrays 
    fp = fopen(FILENAME, "r");
    cnt=0;
    while(fgets(line, 260, fp))
    {
        buf = strtok(line, DELIM);
        while(buf)  
        {
            if((strlen(buf) > 0) && (buf[0] != '\t') && (buf[0] != '\n') && (buf[0] != '\0')&& (buf[0] > 0))
            {
                strcpy(strings[cnt], buf);
                cnt++; //use as accurate count of words.
            }
            buf = strtok(NULL, DELIM);
        }
    }
    fclose(fp);
    //now get most frequent word
    //sort
    qsort(strings, cnt, sizeof(char*), sortstring);
    distinct = 1;
    mostFreq = 1; //every word will occur once
    wordKeep[0]=0;
    for(i=0;i<cnt-1;i++)
    {
        //depends on a successful sort (alphabetization)
        if(strlen(strings[i]) >0)
        {
            if(strcmp(strings[i], strings[i+1]) == 0)
            {
                mostFreq++;
                if(mostFreq > mostFreqKeep) 
                {
                    strcpy(wordKeep, strings[i]);
                    mostFreqKeep = mostFreq;
                }
            }
            else
            {
                mostFreq = 1;
                distinct++; 
            }
        }
    }
    printf("number of words: %d\nNumber of distinct words:%d\nmost frequent word: %s - %d\n", cnt, distinct, wordKeep, mostFreqKeep);

    freeMemory(cnt);
    getchar();
    return 0;
}

int longestWord(char *file, int *nWords)
{
    FILE *fp;
    int cnt=0, longest=0, numWords=0;
    char c;
    fp = fopen(file, "r");
    while ( (c = fgetc ( fp) ) != EOF )
    {
        if ( isalpha ( c ) ) cnt++;
        else if ( ( ispunct ( c ) ) || ( isspace ( c ) ) )
        {
            (cnt > longest) ? (longest = cnt, cnt=0) : (cnt=0);
            numWords++;
        }
    }
    *nWords = numWords;
    fclose(fp);
    return longest+1;
}

void allocMemory(int numStrings, int max)
{
    int i;
    strings = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
    for(i=0;i<numStrings; i++)
    {
      strings[i] = calloc(sizeof(char)*max + 1, sizeof(char));
    }
}

void freeMemory(int numStrings)
{
    int i;
    for(i=0;i<numStrings; i++)
        if(strings[i]) free(strings[i]);
    free(strings);  
}

static int sortstring( const void *str1, const void *str2 )
{
    const char *rec1 = *(const char**)str1;
    const char *rec2 = *(const char**)str2;
    int val = strcmp(rec1, rec2);

    return val;
}
于 2013-09-28T01:01:22.833 回答
0

我给你写了程序,见源码:http: //olegh.cc.st/src/words.c.txt 当然,没有检查特殊情况,比如单行很多单词,不同的单词数量> 16,000等. 但是,您可以获得的基本代码:

运行示例:

$ cat aaa.txt
aaa
bbb
ccc
aaa
xxx
aaa
cc

$ cc words.c ; ./a.out aaa.txt
   1    xxx
   1    ccc
   1    bbb
   1    cc
   3    aaa
于 2013-09-27T23:19:13.353 回答
0

您可以使用一个简单的数据库来计算输入文本中的不同字数。为简单起见,我建议使用SQLite。下面我添加了一些示例代码(为简洁起见,我省略了错误处理)。

为了阅读单词,我采用了一种方法,使用 .将单行读入缓冲区fgets。我注意到,只要您可以保证缓冲区始终足够大以容纳输入文件中的实际行,这种方法就可以很好地工作。否则,单词在缓冲区的末尾被拆分,需要以某种方式处理。

用于解析我使用的文本strtok。在实施过程中,我了解到很难让单词分隔符正确。除此之外,这种方法完全忽略了可能的拼写差异(例如,大写)和其他相同单词的变形,因此可能会对结果产生负面影响。

一旦数据进入数据库,查询语言就非常适合制定查询以获得最大(不同)字数或词频。因此,我认为当您想从输入文本计算多个统计信息时,这种灵活的方法具有优势,因为您不必在 C 中实现每个特殊情况。为了测试,我将关于 SQLite 的 Wikipedia 文章的一部分复制到文件words.txt.

这是示例:

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

#define DELIM " \r\n\t,.-;:_#+*\\=)(/&%$§\"“”!1234567890}][{'"
#define BUFSIZE 4096
#define SQLSIZE 256

int print_row(void* p, int ncols, char **values, char **names) {
    for (int i = 0; i < ncols; i++)
        printf("| %15s : %15s %s", names[i], values[i], i<ncols-1?"":"|\n");
    return 0;
}

int main(int argc, char * argv[]) {
    /* open infile */
    FILE * infile = fopen("words.txt", "r");
    /* initialize database */
    sqlite3 *db_handle = 0;
    sqlite3_open(":memory:", &db_handle);
    sqlite3_exec(db_handle, "CREATE TABLE word (word TEXT);", 0, 0, 0);
    /* parse file, populate db */
    char buf[BUFSIZE], sql[SQLSIZE], *word;
    while(fgets(buf, BUFSIZE, infile))
        for (word = strtok(buf, DELIM); word != 0; word = strtok(0, DELIM)) {
            snprintf(sql, SQLSIZE, "INSERT INTO word VALUES ('%s');", word);
            sqlite3_exec(db_handle, sql, 0, 0, 0);
        }
    /* count of words */
    sqlite3_exec(db_handle,
                 "SELECT COUNT(word) AS total_words FROM word;",
                 print_row, 0, 0);
    /* count of distinct words */
    sqlite3_exec(db_handle,
                 "SELECT COUNT(DISTINCT word) AS distinct_words FROM word;",
                 print_row, 0, 0);
    /* top five most frequent words */
    sqlite3_exec(db_handle,
                 "SELECT word, COUNT(*) AS count FROM word "
                 "GROUP BY word ORDER BY count DESC LIMIT 5;",
                 print_row, 0, 0);
    sqlite3_close(db_handle);
}

这是我的输出:

$ gcc test.c -std=c99 -lsqlite3 && ./a.out 
|     total_words :             561 |
|  distinct_words :             314 |
|            word :          SQLite |           count :              17 |
|            word :              is |           count :              16 |
|            word :             the |           count :              15 |
|            word :               a |           count :              14 |
|            word :              to |           count :              12 |

以供参考:

于 2013-09-29T21:09:34.993 回答