寒假做業 疫情統計(2/2)

一、前言

這個做業屬於哪一個課程 班級連接
這個做業要求在哪裏 做業要求
這個做業的目標 使用github、規範代碼
做業正文 做業正文
其餘參考文獻 暫無

二、PSP

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 10 10
Estimate 估計這個任務須要多少時間 490 470
Development 開發 240 210
Analysis 需求分析 (包括學習新技術) 30 30
Design Spec 生成設計文檔 10 10
Design Review 設計複審 10 10
Coding Standard 代碼規範 (爲目前的開發制定合適的規範) 20 15
Design 具體設計 10 10
Coding 具體編碼 240 210
Code Review 代碼複審 30 40
Test 測試(自我測試,修改代碼,提交修改) 470 470
Reporting 報告 10 10
Test Repor 測試報告 10 10
Size Measurement 計算工做量 10 10
Postmortem & Process Improvement Plan 過後總結, 並提出過程改進計劃 20 20
合計 890 870

三、思路描述

<img src="https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200205215926796-2062364536.png" style="width:200px"> ![]()html

四、實現過程

<img src="https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200205222243740-754093877.png" style="width:220px"> ![]()vue

五、代碼說明

這裏是代碼地址,有詳細註釋

命令行參數與統計結果的數據結構以下:

代碼僅由如下三部分構成,共130餘行:node

1.得到命令行參數的代碼:

if(argv[0]!='list') throw new Error('僅能接受list命令!')
   argv.slice(1).forEach(v => {
      var checked = false  //checked爲true,說明該參數是一個以-爲前綴的key
      for (item of Object.keys(CmdParam))
         if (v == '-' + item) {
            reading = item
            checked = true
            break
         }
      !checked && CmdParam[reading].push(v) //統計鍵值對
   })
   if(!fs.existsSync(CmdParam.log[0])) throw new Error('輸入的日誌目錄不存在!')
   if (fs.readdirSync(CmdParam.log[0]).sort().reverse()[0].split('.')[0] < CmdParam.date[0])
      throw new Error('日期超出範圍!(-date不會提供在日誌最晚一天後的日期)');
   if (!CmdParam.date[0]) 
      return fs.readdirSync(CmdParam.log[0]).sort().reverse()[0].split('.')[0].split('-') //最大日期
   else //指定了日期
      return CmdParam.date[0].split('-')

2.匹配文件內容的代碼:

data = data.split('\n')   //分行,data是單個文件內的所有數據
   data.forEach((line) => {
      var res = []
      function match(reg, hasTwoPvovinces) { //匹配正則,清洗數據以及初始化
         if (/\/\//.test(line)) return false //若是是註釋,忽略掉
         var res = reg.exec(line)
         if (!res) return
         for (key of Object.keys(Total)) { //初始化數據數字爲Number類型,防止NaN
            if (!Total[key][res[1]]) { //非undefined類型表明已經初始化過
               provinces.add(res[1])  //順便收集惟一省份
               Total[key][res[1]] = 0
            }
            if (hasTwoPvovinces && !Total[key][res[2]]) { //同上,而且判斷要收集第三項數據
               provinces.add(res[2])  //順便收集惟一省份
               Total[key][res[2]] = 0
            }
         }
         return res.slice(1, 4) //返回正則匹配的組內容
      }
      if (res = match(/(\S{2,3})\s新增 感染患者 (\d*)人/g))  //正則並收集數據
         Total.ip[res[0]] += Number(res[1])
      if (res = match(/(\S{2,3})\s新增 疑似患者 (\d*)人/g))
         Total.sp[res[0]] += Number(res[1])
      if (res = match(/(\S{2,3})\s疑似患者 流入 (\S{2,3})\s(\d*)人/g, true)) {
         Total.sp[res[0]] -= Number(res[2])
         Total.sp[res[1]] += Number(res[2])
      }
      if (res = match(/(\S{2,3})\s感染患者 流入 (\S{2,3})\s(\d*)人/g, true)) {
         Total.ip[res[0]] -= Number(res[2])
         Total.ip[res[1]] += Number(res[2])
      }
      if (res = match(/(\S{2,3})\s死亡 (\d*)人/g)) {
         Total.ip[res[0]] -= Number(res[1])
         Total.dead[res[0]] += Number(res[1])
      }
      if (res = match(/(\S{2,3})\s治癒 (\d*)人/g)) {
         Total.cure[res[0]] += Number(res[1])
         Total.ip[res[0]] -= Number(res[1])
      }
      if (res = match(/(\S{2,3})\s疑似患者 確診感染 (\d*)人/g)) {
         Total.ip[res[0]] += Number(res[1])
         Total.sp[res[0]] -= Number(res[1])
      }
      if (res = match(/(\S{2,3})\s排除 疑似患者 (\d*)人/g))
         Total.sp[res[0]] -= Number(res[1])
   })

3.整理數據並輸出的代碼:

var provincesSorted = []
   for (let item of Provinces.keys()) { //提取集合裏的省份
      provincesSorted.push(item)
   }
   provincesSorted = provincesSorted.sort((a, b) => { //進行漢字拼音排序
      return prior.indexOf(a) - prior.indexOf(b)
   })
   for (let item of Object.keys(Total)) {  //統計'全國'的數據
      let sum = 0
      for (let num of Object.values(Total[item]))
         sum += num
      Total[item]['全國'] = sum
   }
   provincesSorted.unshift('全國') //確保‘全國’必定在其餘省份的前面
   if (!CmdParam.type.length) CmdParam.type = ['ip', 'sp', 'cure', 'dead'] // 不指定-type即爲輸出所有四項
   provincesSorted.forEach((v) => {
      if (!(CmdParam.province.length == 0 || CmdParam.province.includes(v))) return //篩選-province省份
      article += `${v}`   //開始處理輸出數據的附加項-type
      if (CmdParam.type.includes('ip')) article += ` 感染患者${Total.ip[v]}人`
      if (CmdParam.type.includes('sp')) article += ` 疑似患者${Total.sp[v]}人`
      if (CmdParam.type.includes('cure')) article += ` 治癒${Total.cure[v]}人`
      if (CmdParam.type.includes('dead')) article += ` 死亡${Total.dead[v]}人`
      article += `\n`
   })
   article += `// 該文檔並不是真實數據,僅供測試使用\n// 命令:node InfectStatistic ${cmd}`
   fs.writeFileSync(CmdParam.out[0], article, 'utf-8')  //最後寫入文件

六、單元測試截圖和描述

1.正確性測試

2.日誌記錄混合

<!--<img src="https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200205232016472-1469081961.png" style="width:500px">-->git

測試結果

<!--<img src="https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200206113916675-940302290.png" style="width:700px">-->es6

3.非法時間測試

最晚日誌日期的當天,能夠正常輸出

最晚日誌日期的下一天,拋出錯誤

4.同時限定省份和類型

5.不提供日期參數,則設置爲日誌最大日期

6.mocha與chai單元測試框架結果

七、覆蓋率優化和性能測試,性能優化截圖和描述

尷尬的地方來了, 最強的覆蓋率工具Istanbul沒法傳入命令行額外參數,這就使其永遠沒法覆蓋到佔比不小的參數處理部分, 覆蓋率也就失去了意義... 折騰了好久也沒能找到合適的替代品(也許,幾乎沒有人會在命令行node裏傳額外參數吧) 因此我只能,把命令行參數處理部分換掉,以下: 分析:拋出Error錯誤的行數沒法覆蓋,小部分二選一的分支沒法覆蓋。github

<div style="display:flex;"> <img src="https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200205233259638-1567344822.png"> <img src="https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200205235227733-1355919960.png"> </div> 減小代碼耦合會使代碼更簡潔易懂、後期維護成本低,但也會略微損失性能,比方說用迭代器遍歷對象的鍵。 性能優化方面,在採起「正則預編譯」、「手動列省份順序來替換漢字排序localeCompare()」的措施後,耗時明顯下降。 ![](https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200214181125789-844964291.png) ![](https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200214181132612-639554039.png) ![](https://img2018.cnblogs.com/blog/1918331/202002/1918331-20200214181152453-399772363.png) 待完善的部分:代碼風格的面向對象部分不足;改成異步讀寫文件會提升效率,但因爲處理順序的限制,理論上講性能提高頗有限。web

八、git倉庫連接、代碼規範連接

倉庫連接 代碼規範連接性能優化

九、心路歷程和收穫

最大的感覺就是,因爲第一次接觸單元測試和覆蓋率,來回折騰了好久,尤爲是對IDE沒有很好支持的人來講。 (jetbrains全家桶真的太強了...) 因爲本身英語很爛,看不少插件和庫的教程也是迷迷糊糊,但願本身能更好提升探索未知技術的能力。 而後是撰寫博客和完備的測試,這對初入茅廬的我略有陌生,可是它對養成良好的代碼習慣和反思本身大有裨益。 最後是習慣於使用github很是重要,完善的項目管理功能能夠幫助咱們專一於代碼自己,而沒必要花心思在版本迭代、雲端備份等雞零狗碎的東西上。websocket

十、技術路線圖相關的5個倉庫

新冠肺炎地圖:涉及不少地圖相關應用,以及不少eCharts特性的實踐 vue移動端耦合度更高的demo:基於移動端的vue項目,不過少部分特性已通過時 聊天室:簡易的websocket的demo,熟悉websocket-client的相關API 新冠肺炎數據:對丁香園網站的新冠肺炎數據爬取,並用eCharts進行彙總展現 es6全面的教程:但仍是要結合實際,好比generator用的人實在太少了數據結構

相關文章
相關標籤/搜索