實現一個簡單的程式碼字計數器(一)
前面的文章裡已經介紹瞭如何分割字串,部落格地址在這裡
這裡打算分幾篇文章來寫:
- 分割字串
- 實現一個簡單的程式碼字計數器(一)
- 實現一個簡單的程式碼字計數器(二)
- 實現一個簡單的程式碼字計數器(三)
- 實現一個簡單的程式碼字計數器(四)
網際網路上有很多字計數器,但是大部分都是統計一個文本里的字數,在程式碼中的字計數和一段文本里的計數不太一樣;比如下面的程式碼中計數"name"的個數,程式碼中單詞(字)的個數是有用的;所以這篇文章裡先談一下程式碼字計數器的好處:
用處如下:首先是可以定位比較重要的物件,因為一般出現頻率較高的單詞可能在某個函式中比較重要。就拿我上面的程式碼舉例子,如果逐行看下來可能並不知道我這個類想幹什麼,但是根據單詞出現頻率可以推斷出是和name和address的一個類;有人會說這樣並不明顯,好,我們舉下一個例子:
bool CSetting::ReadValue( CRegKey ®Key, const wchar_t *valName ) { // bool, int, hotkey, color if (type==CSetting::TYPE_BOOL || (type==CSetting::TYPE_INT && this[1].type!=CSetting::TYPE_RADIO) || type==CSetting::TYPE_HOTKEY || type==CSetting::TYPE_HOTKEY_ANY || type==CSetting::TYPE_COLOR) { DWORD val; if (regKey.QueryDWORDValue(valName,val)==ERROR_SUCCESS) { if (type==CSetting::TYPE_BOOL) value=CComVariant(val?1:0); else value=CComVariant((int)val); return true; } return false; } // radio if (type==CSetting::TYPE_INT && this[1].type==CSetting::TYPE_RADIO) { ULONG len; DWORD val; if (regKey.QueryStringValue(valName,NULL,&len)==ERROR_SUCCESS) { CString text; regKey.QueryStringValue(valName,text.GetBuffer(len),&len); text.ReleaseBuffer(len); val=0; for (const CSetting *pRadio=this+1;pRadio->type==CSetting::TYPE_RADIO;pRadio++,val++) { if (_wcsicmp(text,pRadio->name)==0) { value=CComVariant((int)val); return true; } } } else if (regKey.QueryDWORDValue(valName,val)==ERROR_SUCCESS) { value=CComVariant((int)val); return true; } return false; } // string if (type>=CSetting::TYPE_STRING && type<CSetting::TYPE_MULTISTRING) { ULONG len; if (regKey.QueryStringValue(valName,NULL,&len)==ERROR_SUCCESS) { value.vt=VT_BSTR; value.bstrVal=SysAllocStringLen(NULL,len-1); regKey.QueryStringValue(valName,value.bstrVal,&len); return true; } return false; } // multistring if (type==CSetting::TYPE_MULTISTRING) { ULONG len; if (regKey.QueryMultiStringValue(valName,NULL,&len)==ERROR_SUCCESS) { value.vt=VT_BSTR; value.bstrVal=SysAllocStringLen(NULL,len-1); regKey.QueryMultiStringValue(valName,value.bstrVal,&len); for (int i=0;i<(int)len-1;i++) if (value.bstrVal[i]==0) value.bstrVal[i]='\n'; return true; } else if (regKey.QueryStringValue(valName,NULL,&len)==ERROR_SUCCESS) { value.vt=VT_BSTR; value.bstrVal=SysAllocStringLen(NULL,len); regKey.QueryStringValue(valName,value.bstrVal,&len); if (len>0) { value.bstrVal[len-1]='\n'; value.bstrVal[len]=0; } return true; } return false; } Assert(0); return false; }
這段程式碼是我從其他部落格直接拷貝過來的一部分,是一個ReadValue函式,如果逐行讀下來很有可能並不知道這段程式碼想表達什麼,但是根據單詞出現頻率發現出現比較多的是"value"這個單詞,所以我們可以知道這個函式的核心一定是value。然後就可以直接觀看和value相關的程式碼,發現value第一次出現在函式內部並不是通過定義,那麼由於不知道其他程式碼我們可以假定這個value可能是個全域性變數也可能是個類;再進一步會發現value多數都是賦值操作,所以就可以推測出這個ReadValue函式的用途可能是將資料賦值到一個類成員value中。通過這種方式能比較快速的瞭解函式的用途。
另一個用處是可以更好的理解輸入的用途,比如在上面的ReadValue函式中,輸入為regKey和valName,我們可以發現regKey和valName基本上出現次數相近而且基本是同時在使用;所以我們可以推斷這兩個變數很有可能是出自同一個物件的,因為2個變數需要同時進行更新。
再有用處就是:經常出現的模式是在程式碼的一部分中頻繁地使用單詞,並且在這一部分之外很少使用。這可能意味著這部分程式碼集中於使用一個特定的物件,它闡明瞭這部分程式碼的職責。