设计题目
1.
文本文件单词统计
1.1
【问题描述】
编写一个文本文件单词统计的程序,包括建立文件、单词统计、单词查询、单词定位的功能。
1.2
【基本要求】
程序应先询问用户的
ID
号
(ID
号包括两个大写字母和
4
位数字
)
,例如
:
请输入用户
ID
号
:
AB1234
程序应对输入的
ID
号验证,符合
ID
号要求的格式,然后程序提示四种选择
:
(1)
建立文件
(2)
单词统计
(3)
单词查询及定位
(4) 退出
注意:
i)
文件至少包含
50
个英文单词(一定出现重复的单词,且一定包含数字)
ii)
文档不规范,单词之间可能不只有一个空格,并且有加引号的一些单词“
jiaozi
”
加引号的单词算单词,但数字不算单词
iii)
逐行扫描文本文件,计算文档中单词总数,及各个单词出现的频次,并且按照单词首字母
abcd
……
的顺序排列,显示并生成
soft.txt
文件
iv)
查询任意给出的单词是否存在,如果不存在,在屏幕上输出“
查无此词!
”;如果存在,显示单词
出现的总次数,并且详细列出其 出现的位置。
例如:
请您输入待查询的词:
of
单词
of
共出现了
2
次;
第
1
次出现在第
1
行,第
5
个位置;
第
2
次出现在第
3
行,第
1
个位置。
请您输入待查询的词:
完整代码
#include<bits/stdc++.h>
using namespace std;
string s,word_text, words;
vector<string> words_single; //存放要查找的单词 方便比较
vector<string> v;
vector<string> v3;
vector<string> v4;
int n,row,col,temp;
string j = "%"; //解决最后一次出现的位置为0的问题
int find_word(int col)
{
words_single.insert(words_single.end(),j);
for(int i=col;i<v3.size();i++)
{
words_single.insert(words_single.end(),v3[i]);
}
int sub_num2 = find(words_single.begin(),words_single.end(),words)-words_single.begin();
if(sub_num2<words_single.size())
{
n++;
col += sub_num2;
int temp_col = col;
if(col>11)
{
row = col/11+1;
temp_col = col%11;
}
printf("它在文件output中第%d次出现的位置位于第%d行第%d列\n",n,row,temp_col);
words_single.clear();
find_word(col);
}
else
{
return 0;
}
}
int main()
{
int flag=0;
bool sign = 0;
printf("请输入用户ID号:");
cin >> s;
vector<string> v2;
vector<int> word_num;
int num; //去重后单词的个数
int sub_num;
//检查ID号格式是否正确 两个大写字母和四个数字
regex pattern("[A-Z][A-Z]\\d{4}"); //正则
sign = std::regex_match(s,pattern);
while(sign)
{
printf("请选择操作:\n");
cout << "1 建立文件" << endl << "2 单词统计" <<endl << "3 单词查询及定位" << endl <<"4 退出" <<endl;
scanf("%d",&flag);
string filename("output.txt"); //输入时文本的存储空间
fstream output_fstream;
string filename2("soft.txt") ; //词频统计后单词的存储空间
fstream softfile;
if(flag ==1) //建立文件
{
output_fstream.open(filename, std::ios_base::out); //文件名 与打开方式
if (!output_fstream.is_open()) {
cerr << "Failed to open " << filename << '\n';
}
else {
cout << "请输入您的文本:" ;
cin.ignore(); //忽略换行 保证getline可以正确执行
getline(cin, word_text);
char e[10000];
strcpy(e, word_text.c_str()); //将string转为char
const char *D = "^ "; //遇到这些字符时不作处理
char *P;
P = strtok(e,D);
while(P)
{
v4.push_back(P);//在容器尾部加入一个数据
P=strtok(NULL,D);
}
for(int i=0;i<v4.size();i++)
{
if(i%11 == 0 and i!=0)
{
output_fstream << endl; //解决输入时 遇空格中断
}
output_fstream << v4[i] << " "; //解决输入时 遇空格中断
}
cerr << "输入成功,请打开'output.txt'文件自行查看" << endl<<endl;
}
output_fstream.close() ;
}
//对文档进行处理,使其规范化
char c[10000];
strcpy(c, word_text.c_str()); //将string转为char
const char *d = "!\\" "@#¥%……&*()—+=!$^&_}{}[];''""?></,\n 1234567890"; //遇到这些字符时不作处理
char *p;
p = strtok(c,d);
if(flag==2) //词频统计
{
while(p)
{
v.push_back(p);//在容器尾部加入一个数据
p=strtok(NULL,d);
}
sort(v.begin(),v.end()); //先排序 后统计
for(int i=0;i<v.size();i++){
int cnt1 =0 ; //和计数方式有关
cnt1 = count(v2.begin(),v2.end(),v[i]); //如果这个单词之前没出现过
if(!cnt1)
{
int cnt = count(v.begin(),v.end(),v[i]);
word_num.insert(word_num.end(),cnt); // 次数
v2.insert(v2.end(),v[i]); // 单词
}
else
{
continue;
}
}
//将结果写入到文件当中
softfile.open(filename2, std::ios_base::out); //文件名 与打开方式
if (!softfile.is_open()) {
cerr << "Failed to open " << filename << '\n';
}
else {
for(int i =0;i<v2.size();i++)
{
cout << v2[i] << " " << word_num[i]<<endl;
softfile << v2[i] << " " << word_num[i]<<endl; //解决输入时 遇空格中断
}
cerr << "输入成功,请打开'soft.txt'文件自行查看" << endl<<endl;
}
output_fstream.close() ;
}
else if(flag==3) //单词查询及定位
{
int col = 0;
while(p)
{
v3.push_back(p);//在容器尾部加入一个数据
p=strtok(NULL,d);
}
n = 0; //置零,防止第几次叠加不是目标词的次数而出错
cout<< "请输入您要查询的词汇:" << endl;
cin >> words;
int cnt1 = count(v2.begin(),v2.end(), words); //判断目标单词是否存在
if(!cnt1)
{
cout << "查无此词"<<endl;
}
else if(cnt1)
{
cout <<"您输入的待查词是:" << words<<endl;
sub_num = find(v2.begin(),v2.end(),words)-v2.begin(); //找到目标单词的下标
printf("单词出现的次数是:%d \n",word_num[sub_num]); //在存放次数的数组中找到次数
row = 1;
find_word(col);
}
words.clear();
v3.clear() ;
}
else if(flag==4)
{
cout << "您已退出该程序";
break;
}
}
while(!sign)
{
printf("ID号格式为两个大写字母和四个数字,SD形如:AB1234。 \n");
printf("ID号格式有误请重新输入 \n");
main();
}
return 0;
}
代码分析
万能头文件 全局变量声明
#include<bits/stdc++.h>
using namespace std;
string s,word_text, words;
vector<string> words_single; //存放要查找的单词 方便比较
vector<string> v; //用于存放初始输入经过规格化的文本
vector<string> v3; //工具vector
vector<string> v4; //工具vector
int n,row,col,temp; //n 第几次出现 row 行数 col 列数 temp工具人
string j = "%"; //解决最后一次出现的位置为0的问题
好的点是全局变量声明后,在整个程序段中都可以使用
然后,声明了四个vector数组 缺点就是占的空间比较大,优点的话是不会发生数据的错乱或者混淆
功能三的实现 实现文件中单词的定位查询
int find_word(int col) //col 用于记录行数
{
words_single.insert(words_single.end(),j); //j就是字符串"%"
for(int i=col;i<v3.size();i++)
{
words_single.insert(words_single.end(),v3[i]);
}
//sub_num2 存储目标单词的位置
int sub_num2 = find(words_single.begin(),words_single.end(),words)-words_single.begin();
if(sub_num2<words_single.size())
{
n++;
col += sub_num2;
int temp_col = col;
if(col>11)
{
row = col/11+1;
temp_col = col%11;
}
printf("它在文件output中第%d次出现的位置位于第%d行第%d列\n",n,row,temp_col);
words_single.clear();
find_word(col);
}
else
{
return 0;
}
}
算法:切片,重新输入 然后定位查询
在words_single开始插入字符 “%”的原因是,占起址为0的空间,然后减的时候减去0刚好得到对应的位置,也就是单词对应的位置
col用作标志位,每次从col的下一个开始再次存入数组中,然后采用find对新的数组进行查找相关词,找到后,再次重找到位置的下一个切片存入数组中,再次遍历查询,直到没有找到目标词,然后退出
v3是在主函数中经过处理的 char 类型的数组,以一个单词为单位进行遍历
主函数中依次实现四个功能
int main()
{
int flag=0; //标志用于指定进入哪个功能
bool sign = 0; // ID号是否符合格式的代码
printf("请输入用户ID号:");
cin >> s;
vector<string> v2; //字符型数组v2
vector<int> word_num; //
int num; //去重后单词的个数
int sub_num; //功能2中查找对应单词出现次数的标志
//检查ID号格式是否正确 两个大写字母和四个数字
regex pattern("[A-Z][A-Z]\\d{4}"); //正则 判断是否符合格式要求
sign = std::regex_match(s,pattern);
while(sign) //当符合要求后进入
{
printf("请选择操作:\n");
cout << "1 建立文件" << endl << "2 单词统计" <<endl << "3 单词查询及定位" << endl <<"4 退出" <<endl;
scanf("%d",&flag); //要进行哪一项操作
string filename("output.txt"); //输入时文本的存储空间 建立文件output
fstream output_fstream;
string filename2("soft.txt") ; //词频统计后单词的存储空间
fstream softfile;
if(flag ==1) //建立文件
{
output_fstream.open(filename, std::ios_base::out); //文件名 与打开方式 此处以out方式打开
if (!output_fstream.is_open()) {
cerr << "Failed to open " << filename << '\n';
}
else {
cout << "请输入您的文本:" ;
cin.ignore(); //忽略换行 保证getline可以正确执行
getline(cin, word_text); 将输入的内容全部接收 包括空格
char e[10000]; //空间大点,存的单词可以多
strcpy(e, word_text.c_str()); //将string转为char
const char *D = "^ "; //遇到这些字符时不作处理
char *P;
P = strtok(e,D);
while(P)
{ //此处v4用于将文本以单词为单位输入
v4.push_back(P); //在容器尾部加入一个数据
P=strtok(NULL,D);
}
for(int i=0;i<v4.size();i++)
{
if(i%11 == 0 and i!=0)
{
output_fstream << endl; //解决输入时 遇空格中断
}
output_fstream << v4[i] << " "; //解决输入时 空格消失 v4是一个char类型的没有空格的数组
}
cerr << "输入成功,请打开'output.txt'文件自行查看" << endl<<endl;
}
output_fstream.close() ; //关闭文件
}
//对文档进行处理,使其规范化 为功能二 词频统计做准备
char c[10000];
strcpy(c, word_text.c_str()); //将string转为char
const char *d = "!\\" "@#¥%……&*()—+=!$^&_}{}[];''""?></,\n 1234567890"; //遇到这些字符时,单词统计不作处理
char *p;
p = strtok(c,d);
if(flag==2) //词频统计
{
while(p)
{ //压入容器中便于遍历处理
v.push_back(p); //在容器尾部加入一个数据
p=strtok(NULL,d);
}
sort(v.begin(),v.end()); //先排序 后统计 按A-Z和a-z 的方式进行统计
for(int i=0;i<v.size();i++){
int cnt1 =0 ; //和计数方式有关
cnt1 = count(v2.begin(),v2.end(),v[i]);
if(!cnt1) //如果这个单词之前没出现过
{
int cnt = count(v.begin(),v.end(),v[i]); //计数 统计该单词一共出现了几次
word_num.insert(word_num.end(),cnt); // word_num 容器 用于存放次数
v2.insert(v2.end(),v[i]); // v2 用于存放单词
} //需要注意的是,这个位置的单词和对应的次数 必须分别存放在数组下标相同的位置
else
{
continue; //如果这个单词出现过,就不再统计
}
}
//将结果写入到文件当中 该文件已 Key:value 方式存放
softfile.open(filename2, std::ios_base::out); //文件名 与打开方式
if (!softfile.is_open()) {
cerr << "Failed to open " << filename << '\n';
}
else {
for(int i =0;i<v2.size();i++)
{
cout << v2[i] << " " << word_num[i]<<endl; //在显示器上显示统计结果
softfile << v2[i] << " " << word_num[i]<<endl; //统计结果存入文档中,解决输入时 遇空格中断
}
cerr << "输入成功,请打开'soft.txt'文件自行查看" << endl<<endl; //两次换行 界面简洁
}
output_fstream.close() ; //文件关闭
}
else if(flag==3) //单词查询及定位
{
int col = 0;
while(p)
{
v3.push_back(p);//在容器尾部加入一个数据
p=strtok(NULL,d);
}
n = 0; //置零,防止第几次叠加不是目标词的次数而出错
cout<< "请输入您要查询的词汇:" << endl;
cin >> words;
int cnt1 = count(v2.begin(),v2.end(), words); //判断目标单词是否存在
if(!cnt1)
{
cout << "查无此词"<<endl;
}
else if(cnt1)
{
cout <<"您输入的待查词是:" << words<<endl;
sub_num = find(v2.begin(),v2.end(),words)-v2.begin(); //找到目标单词的下标
printf("单词出现的次数是:%d \n",word_num[sub_num]); //在存放次数的数组中找到次数
row = 1;
find_word(col); //调用查找功能
}
words.clear();
v3.clear() ;
}
else if(flag==4)
{
cout << "您已退出该程序";
break;
}
}
while(!sign)
{
printf("ID号格式为两个大写字母和四个数字,SD形如:AB1234。 \n");
printf("ID号格式有误请重新输入 \n");
main();
}
return 0;
}