1. 程式人生 > >實現一個簡單的程式碼字計數器(一)

實現一個簡單的程式碼字計數器(一)

前面的文章裡已經介紹瞭如何分割字串,部落格地址在這裡

這裡打算分幾篇文章來寫:

網際網路上有很多字計數器,但是大部分都是統計一個文本里的字數,在程式碼中的字計數和一段文本里的計數不太一樣;比如下面的程式碼中計數"name"的個數,程式碼中單詞(字)的個數是有用的;所以這篇文章裡先談一下程式碼字計數器的好處:

image.png

用處如下:首先是可以定位比較重要的物件,因為一般出現頻率較高的單詞可能在某個函式中比較重要。就拿我上面的程式碼舉例子,如果逐行看下來可能並不知道我這個類想幹什麼,但是根據單詞出現頻率可以推斷出是和name和address的一個類;有人會說這樣並不明顯,好,我們舉下一個例子:

bool CSetting::ReadValue( CRegKey &regKey, 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個變數需要同時進行更新。

再有用處就是:經常出現的模式是在程式碼的一部分中頻繁地使用單詞,並且在這一部分之外很少使用。這可能意味著這部分程式碼集中於使用一個特定的物件,它闡明瞭這部分程式碼的職責。