nowcoder-HJ-19


HJ16 购物单

1 题目描述

开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。

处理:

  1. 记录最多8条错误记录,循环记录,最后只用输出最后出现的八条错误记录。对相同的错误记录只记录一条,但是错误计数增加。最后一个斜杠后面的带后缀名的部分(保留最后16位)和行号完全匹配的记录才做算是“相同”的错误记录
  2. 超过16个字符的文件名称,只记录文件的最后有效16个字符;
  3. 输入的文件可能带路径,记录文件名称不能带路径。也就是说,哪怕不同路径下的文件,如果它们的名字的后16个字符相同,也被视为相同的错误记录
  4. 循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准.

数据范围:错误记录数量满足 $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;
}

文章作者: Vyron Su
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Vyron Su !