计算每个单词的唯一单词数和出现次数

时间:2013-09-15 19:54:41

标签: c++

CSCI-15作业#2,字符串处理。 (60分)截止日期为2013年9月23日

您不能在此程序中使用C ++字符串对象。

编写一个C ++程序,使用ifstream getline()方法从文件中读取文本行,使用strtok()将行标记为单词(“标记”),并保存文件中数据的统计信息。您的输入和输出文件名将在命令行中提供给您的程序,您将使用argcargv[]访问该文件。

您需要计算单词总数,唯一单词数,每个单词的数量以及行数。此外,请记住并打印文件中最长和最短的单词。如果对于最长或最短的单词存在平局,您可以以任何一致的方式解决该平局(例如,使用找到的第一个或最后一个,但对最长和最短使用相同的方法)。您可以假设这些行包含由空格分隔的单词(连续的小写字母[a-z]),以句点结尾。您可以忽略其他标点符号的可能性,包括所有权或收缩,例如“Jim's house”。文件中最后一行之前的行将在句点之后有一个换行符('\ n')。在数据文件中,省略最后一行的'\ n'。您可以假设这些行不超过100个字符,单个单词不超过15个字母,文件中不会有超过100个唯一单词。

从输入文件中读取行,并将它们回显到输出文件。在输入文件到达文件结尾(或读取长度为零的行,您应将其视为输入数据的结尾)后,打印出现次数为单词,每行一个字/计数对,以及收集的统计信息到输出文件。您还需要创建自己的其他测试文件。此外,您的程序必须与EMPTY输入文件一起正常工作 - 该文件没有统计信息。

测试文件如下所示(正好是4行,最后一行没有NEWLINE):

  快速的棕色狐狸跳过懒狗。   现在是所有好人来帮助他们党的时候了。   我想要的圣诞节就是我的两颗门牙。   快速的棕色狐狸跳过一只懒狗。

将其复制并粘贴到一个小文件中,以进行一项测试。

提示:

使用二维char数组,100行乘16列(为什么不是15?)来保存唯一的单词,以及包含100个元素的1维int数组来保存相关的计数。对于每个单词,扫描数组中的占用行以进行匹配(使用strcmp()),如果找到匹配项,则递增相关计数,否则(超过最后一个单词),将单词添加到该表并将其计数设置为1。

单独的最长单词和最短的单词需要在他们自己的C字符串中保存。 (为什么不能在标记化数据中保留指向它们的指针?)

请记住 - 在最后一行的末尾放置NO NEWLINE,否则您对文件结尾的测试可能无法正常工作。 (这可能导致程序在看到文件结束之前读取零长度的行。)

这不是一个长程序 - 不超过2页代码

这是我到目前为止所做的:

#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<cstring>
using namespace std;

void totalwordCount(ifstream &inputFile)
{
    char words[100][16]; // Holds the unique words.
    char *token;
    int totalCount = 0; // Counts the total number of words.
    // Read every word in the file.
    while(inputFile >> words[99])
    {
        totalCount++; // Increment the total number of words.
        // Tokenize each word and remove spaces, periods, and newlines.
        token = strtok(words[99], " .\n"); 
        while(token != NULL)
        {
            token = strtok(NULL, " .\n");
        }
    } 
    cout << "Total number of words in file: " << totalCount << endl;
}

void uniquewordCount(ifstream &inputFile)
{
    char words[100][16]; // Holds the unique words
    int counter[100];
    char *tok = "0";
    int uniqueCount = 0; // Counts the total number of unique words
    while(!inputFile.eof())
    {
        uniqueCount++;
        tok = strtok(words[99], " .\n");
        while(tok != NULL)
        {
            tok = strtok(NULL, " .\n");
            inputFile >> words[99];
            if(strcmp(tok, words[99]) == 0)
            {
                counter[99]++;
            }
            else
            {
                words[99][15] += 1;
            }
            uniqueCount++;
        }
    }
    cout << counter[99] << endl;
}

int main(int argc, char *argv[])
{
    ifstream inputFile;
    char inFile[12] = "string1.txt";
    char outFile[16] = "word result.txt";

    // Get the name of the file from the user.
    cout << "Enter the name of the file: ";
    cin >> inFile;

    // Open the input file.
    inputFile.open(inFile);

    // If successfully opened, process the data.
    if(inputFile)
    {
        while(!inputFile.eof())
        {        
            totalwordCount(inputFile);
            uniquewordCount(inputFile);
        }
    }
    return 0;
}

我已经注意了如何计算totalwordCount()函数中文件中的单词总数,但在uniquewordCount()函数中,我无法计算唯一单词的总数和计算每个单词的出现次数。我需要在uniquewordCount()函数中更改哪些内容?

1 个答案:

答案 0 :(得分:4)

该程序包含几个被认为有害的问题!为了防止基于完全无意义的分配(如上所述)创建不良软件,以下是一些提示:

  1. 始终测试流读取之后是否成功。使用in.eof()确定流是否处于良好状态是否正常工作!其中一个问题是如果流由于与文件末尾不同的原因而变坏,则会得到无限循环,例如,无法正确解析值(这将设置std::ios_base::failbit但不设置std::ios_base::eofbit
  2. 使用char读取固定大小的a数组in >> a而不设置要读取的字符数限制是C ++拼写gets()的方法!如果你真的认为使用in >> a是正确的方法(参见下一项),你绝对需要设置数组的宽度,例如,使用in >> std::setw(sizeof(a)) >> a。当然,您仍然需要检查此提取是否成功。
  3. 从它的外观来看,你的老师希望你实际使用std::istream::getline()来阅读数组,例如,使用in.getline(a, sizeof(a))(当然,需要检查它是否成功)。
  4. 请注意,格式化的输入,即in >> a已经标记了空格接收的流!在此之后,没有必要对strtok()表示赞同。
  5. 消耗了一个流后,它就被消耗掉了。假设字符不是来自文件,而是来自标准输入,您也无法回放流以再次读取它。我认为你想要将这些值标记化一次并将它们用于这两个目的。
  6. 这更像是一个旁注:在创建流之后,其性质应该对流的内容的处理完全无关紧要(尽管,例如,对于字符串流,您可能希望最终使用{{1}来收集结果}} member:根据str()而不是std::istream来实现您的流处理函数!
  7. 因为你有一个具体的问题(“我需要在uniquewordCount()函数中改变什么吗?”):是的,一切!完全抛弃这个功能,重新思考你需要做什么。基本上,功能的结构应该是

    std::ifstream