CSCI-15作业#2,字符串处理。 (60分)截止日期为2013年9月23日
您不能在此程序中使用C ++字符串对象。
编写一个C ++程序,使用ifstream getline()
方法从文件中读取文本行,使用strtok()
将行标记为单词(“标记”),并保存文件中数据的统计信息。您的输入和输出文件名将在命令行中提供给您的程序,您将使用argc
和argv[]
访问该文件。
您需要计算单词总数,唯一单词数,每个单词的数量以及行数。此外,请记住并打印文件中最长和最短的单词。如果对于最长或最短的单词存在平局,您可以以任何一致的方式解决该平局(例如,使用找到的第一个或最后一个,但对最长和最短使用相同的方法)。您可以假设这些行包含由空格分隔的单词(连续的小写字母[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()
函数中更改哪些内容?
答案 0 :(得分:4)
该程序包含几个被认为有害的问题!为了防止基于完全无意义的分配(如上所述)创建不良软件,以下是一些提示:
in.eof()
确定流是否处于良好状态不是否正常工作!其中一个问题是如果流由于与文件末尾不同的原因而变坏,则会得到无限循环,例如,无法正确解析值(这将设置std::ios_base::failbit
但不设置std::ios_base::eofbit
char
读取固定大小的a
数组in >> a
而不设置要读取的字符数限制是C ++拼写gets()
的方法!如果你真的认为使用in >> a
是正确的方法(参见下一项),你绝对需要设置数组的宽度,例如,使用in >> std::setw(sizeof(a)) >> a
。当然,您仍然需要检查此提取是否成功。std::istream::getline()
来阅读数组,例如,使用in.getline(a, sizeof(a))
(当然,需要检查它是否成功)。in >> a
已经标记了空格接收的流!在此之后,没有必要对strtok()
表示赞同。str()
而不是std::istream
来实现您的流处理函数!因为你有一个具体的问题(“我需要在uniquewordCount()函数中改变什么吗?”):是的,一切!完全抛弃这个功能,重新思考你需要做什么。基本上,功能的结构应该是
std::ifstream