HJ16 购物单
1 题目描述
- 题目链接:HJ19 简单错误记录
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
- 记录最多8条错误记录,循环记录,最后只用输出最后出现的八条错误记录。对相同的错误记录只记录一条,但是错误计数增加。最后一个斜杠后面的带后缀名的部分(保留最后16位)和行号完全匹配的记录才做算是“相同”的错误记录;
- 超过16个字符的文件名称,只记录文件的最后有效16个字符;
- 输入的文件可能带路径,记录文件名称不能带路径。也就是说,哪怕不同路径下的文件,如果它们的名字的后16个字符相同,也被视为相同的错误记录;
- 循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准.
数据范围:错误记录数量满足 $1 \le n \le 100$ ,每条记录长度满足 $1 \le len \le 100$
输入描述:
每组只包含一个测试用例。一个测试用例包含一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
输入描述:
将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开,如:
示例1:
输入: D:\zwtymj\xccb\ljj\cqzlyaszjvlsjmkwoqijggmybr 645
E:\je\rzuwnjvnuz 633
C:\km\tgjwpb\gy\atl 637
F:\weioj\hadd\connsh\rwyfvzsopsuiqjnr 647
E:\ns\mfwj\wqkoki\eez 648
D:\cfmwafhhgeyawnool 649
E:\czt\opwip\osnll\c 637
G:\nt\f 633
F:\fop\ywzqaop 631
F:\yay\jc\ywzqaop 631
D:\zwtymj\xccb\ljj\cqzlyaszjvlsjmkwoqijggmybr 645
输出: rzuwnjvnuz 633 1
atl 637 1
rwyfvzsopsuiqjnr 647 1
eez 648 1
fmwafhhgeyawnool 649 1
c 637 1
f 633 1
ywzqaop 631 2
说明:
由于D:\cfmwafhhgeyawnool 649的文件名长度超过了16个字符,达到了17,所以第一个字符’c’应该被忽略。
记录F:\fop\ywzqaop 631和F:\yay\jc\ywzqaop 631由于文件名和行号相同,因此被视为同一个错误记录,哪怕它们的路径是不同的。
由于循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准,所以D:\zwtymj\xccb\ljj\cqzlyaszjvlsjmkwoqijggmybr 645不会被记录。
2 思路
普通的字符串处理问题,首先我们需要找到文件名,然后获取文件名及其以后的字符串存放在vector数组中(文件名超过16还需要对文件名进行截断,最简单的方法就是找到文件名字符串中空格出现的位置,如果空格位置对应的下标大于16说明文件名需要截断);由于我们需要输出最近的8条错误信息,因而需要有插入顺序,并且还需要计算”相同”错误信息出现的次数,因而需要额外加一个vector
来存放次数。获取到目标字符串后,首先在vector<string>
数组中查找是否已存在这个字符串,若存在则将对应的位置的次数+1,否则插入这个字符串到vector<string>
并插入1到数组vector<int>
中。
#include <string> // string、 substr
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(void){
string info = "";
vector<string> m;
vector<int> n;
while(getline(cin, info)){
int left = 0, right = 0;
while(info[right] != ' '){ // 获取文件名的范围
if(info[right] == '\\') left = right+1;
++right;
}
if(right-left > 16){ // 进行文件名截断
info = info.substr(right-16);
}else{
info = info.substr(left);
}
int i = 0;
for(; i < m.size(); ++i){ // 查询是否已经存在这个错误信息
if(m[i] == info) break;
}
if(i < m.size()){ // 存在错误信息
n[i]++; // 对应次数加1
}else{
m.emplace_back(info); // 不存在这个错误信息
n.emplace_back(1); // 插入并将次数置为1
}
}
int start = m.size()-8; // 只输出8条错误信息
for(start = max(start, 0); start < m.size(); ++start){
cout << m[start] << " " << n[start] << endl;
}
return 0;
}
但使用循环查找浪费时间,可以调用find
函数来查找。使用str.find()
函数在字符串中查找到最后一个反斜杠符号\\
,然后可以得到文件名+行号为str.substr(str.find('\\')
,但str.find()
找到的是第一个反斜杠,但输入的字符串串可能有若干个反斜杠,因而可以考虑从后往前找,即使用str.rfind()
来找最后一个反斜杠。
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(void){
string info = "";
vector<string> m;
vector<int> n;
while(getline(cin, info)){
info = info.substr(info.rfind('\\')+1);
int blank = info.find(' ');
if(blank > 16){
info = info.substr(blank - 16);
}
int i = find(m.begin(), m.end(), info) - m.begin();
if(i >= m.size()){
m.emplace_back(info);
n.emplace_back(1);
}else{
n[i]++;
}
}
int start = m.size()-8;
for(start = max(start, 0); start < m.size(); ++start){
cout << m[start] << " " << n[start] << endl;
}
return 0;
}