詳解C#如何快速獲取助記碼
希望通過本文能讓大家對(duì)C#如何快速獲取助記碼有更深刻的了解,51CTO也向您推薦《C#實(shí)用基礎(chǔ)教程》。
本文實(shí)現(xiàn):
1、以犧牲空間為代價(jià),方便快速地實(shí)現(xiàn)漢字的助記碼獲取。
2、針對(duì)拼音特性,實(shí)現(xiàn)多音字并提供顯式地姓氏調(diào)用方法。
網(wǎng)上關(guān)于使用C#取助記碼的方法很多,不過一般都是采用將每一個(gè)碼有哪些漢字的方法來實(shí)現(xiàn)助記碼的轉(zhuǎn)換,它的缺點(diǎn)是顯而易見的:
1.相當(dāng)于本來應(yīng)該存放在數(shù)據(jù)庫或者是外部的數(shù)據(jù)存放到程序中;
2.利用字符串的定位功能,性能上也不一定好。
在線性表中我們查找指定位置結(jié)點(diǎn)的數(shù)據(jù)是最快的,比如一個(gè)包含10000個(gè)元素的線性表中,無論直接訪問哪一個(gè)位置的數(shù)據(jù)值,只要根據(jù)表的***個(gè)位置就可以直接定位到第9000個(gè)元素的位置,數(shù)組也是一種簡單有效的線性表,需要某個(gè)項(xiàng)目,只要通過編移量即可搞定。
在不使用數(shù)據(jù)庫,直接使用文件做資源,方便配置,完成中文到助記碼的的轉(zhuǎn)換,同時(shí)針對(duì)拼音助記碼,還要實(shí)現(xiàn):1.多音字詞組匹配;2.姓氏專用方法。
同時(shí)五筆碼、四角碼等多種類別也易如反掌。雖然在以犧牲空間為代價(jià),但用空間換得時(shí)間的性能提高,還是非常值得的。
數(shù)據(jù)存放使用數(shù)組
數(shù)組就是一種線性表,我們的解決思路是:
1、每一個(gè)項(xiàng)目對(duì)應(yīng)一個(gè)結(jié)構(gòu),它包括漢字、拼音碼、是否多音字、五筆碼(或其它更多編碼);
2、每一個(gè)漢字直接轉(zhuǎn)換成一個(gè)數(shù)字編碼(ASCII或者是UNICODE),數(shù)字就是數(shù)組下標(biāo);
3、讀取文字串,根據(jù)每一個(gè)漢字取得數(shù)字,直接定位數(shù)組中的位置,取得編碼。
因此我們定義用于存放漢字的助記簡碼的結(jié)構(gòu)(有更多編碼,只要在結(jié)構(gòu)上擴(kuò)充即可):
- private struct ItemWord{
- public int numFlag; //是否多音字
- public char strWord;//當(dāng)前單詞
- public string strSpell1;//輸入碼
- public string strSpell2;//輸入碼
- public string strExt; //多音字保留串
- public string strName;//用于定義姓氏碼
加載助記碼字典
由于要支持拼音及多音字,也支持五筆的助記碼,為了例子方便,編碼表都暫時(shí)存放在d:\myword下,下面以拼音碼的加載為例,首先初始化Itemword中的每一個(gè)項(xiàng)目,通常情況下GBK的實(shí)際漢字?jǐn)?shù)應(yīng)該在20000字左右,從雙字節(jié)的角度來看,最多也就只有64K,因此把我們的數(shù)組定義為64K,即:
- private static readonly int INTMAX = 65536;
- private ItemWord[] stWord = new ItemWord[INTMAX];
在函數(shù)fun_LoadWord中拼音碼hzpy1.txt的加載方法:
- while ((strInput = srFile.ReadLine()) != null){
- chrWord = strInput.ToCharArray();
- numIndex = (int)chrWord[0];
- stWord[numIndex].strWord = chrWord[0];
- stWord[numIndex].strSpell1 = chrWord[2].ToString();
注意,其中最最關(guān)鍵是把讀取的內(nèi)容轉(zhuǎn)成char的數(shù)組,再通過(int)chrWord[0]把它轉(zhuǎn)換為一個(gè)數(shù)組的下標(biāo)值(這個(gè)相對(duì)來說C就簡單許多),再把相應(yīng)內(nèi)容填到數(shù)組中此下標(biāo)項(xiàng)目。對(duì)于五筆碼的讀取方法也一致,非常簡單(更多的其它編碼也不在話下)。不過,拼音碼的多音存儲(chǔ),需要介紹一下,實(shí)際上對(duì)于漢字來說,單音是大多數(shù),只有少部分才是多音字,為了結(jié)構(gòu)更簡單,把多音字是存放在相應(yīng)的漢字結(jié)構(gòu)中,即:
- numIndex = (int)chrWord[0];
- strInput = strInput.Substring(2);
- strInput = strInput.Replace("\t", " ");
- strInput = strInput.Replace(" ", "/");
- stWord[numIndex].strExt = stWord[numIndex].strExt + strInput + "|";
最終strExt中的結(jié)構(gòu)內(nèi)容是“|曾哥/Z|”的格式,它的好處會(huì)在多音碼的展現(xiàn)時(shí)進(jìn)行說明。
從漢字到簡碼
我們先舉例五筆的助記碼實(shí)現(xiàn),對(duì)傳入的漢字串來說,只要提取每一個(gè)漢字,得到對(duì)應(yīng)的字符編碼,再直接提取其對(duì)應(yīng)編碼,由于直接采用下標(biāo)取得編碼,而數(shù)據(jù)又加載在內(nèi)存數(shù)組中,可以用飛速來描述它:
- chrWord = strChinese.ToCharArray();
- numCount = strChinese.Length;
- for (i = 0; i < numCount; i++){
- numIndex = (int)chrWord[i];
- strSpell = strSpell + stWord[numIndex].strSpell2.ToString();
拼音碼,則存在著幾個(gè)主要問題,一個(gè)是姓氏,還有一個(gè)是多音字,多音字的實(shí)現(xiàn),通過詞組模式來處理,即首先它是一個(gè)多音字,即結(jié)構(gòu)中的numFlag標(biāo)志。同時(shí)根據(jù)漢字串往前往后追蹤一個(gè)形成詞組,例如“曾哥”,它雖然來源于姓氏,但是本身已經(jīng)形成一個(gè)受眾很廣的詞,在hzpy2.txt中定義“曾 曾哥 Z”這樣一行內(nèi)容。在多音字時(shí),我們用函數(shù)funFindMulti來定位多音字的編碼:
- strWord = "|" + ch1 + ch2 + "/";
- numPos = stWord[numIndex].strExt.IndexOf(strWord);
- if (numPos >= 0) return stWord[numIndex].strExt.Substring(numPos + strWord.Length, 1);
也就是說,但我們定位漢字“曾”時(shí),首先它是一個(gè)多音字,再根據(jù)詞組“曾哥”對(duì)應(yīng)的編碼,
我們把用于定位的詞組形成前綴“|詞組/”的格式,假定有多個(gè)多音時(shí),可以通過唯一位置定位后,再取得此串后面的字符,即“Z”,所以當(dāng)我們輸入“信曾哥得自信”時(shí),得到拼音助記碼自然就是“XZGDZX”了。因?yàn)樾帐系奶厥庑裕⑶覍?shí)際業(yè)務(wù)中,比較明確地知道,當(dāng)前的內(nèi)容是否是姓名,即我們顯式調(diào)用,而姓名中,也只有在首字時(shí)才發(fā)生按姓的讀音。只要調(diào)用參數(shù)提供是否姓名的開關(guān)(下面的變量IsName,為了文章方便,緊湊格式了)即可:
- if (stWord[numIndex].numFlag > 0 && !IsName){if (i > 0) strThis = funFindMulti(numIndex, chrWord[i - 1], chrWord[i]);
- if (strThis.Length == 0 && i < numCount -1 ) strThis = funFindMulti(numIndex, chrWord[i], chrWord[i + 1]);
- }
- if (IsName && i == 0 && stWord[numIndex].strName.Length > 0)strThis = stWord[numIndex].strName;
- if (strThis.Length == 0)strThis = stWord[numIndex].strSpell1.ToString();
- strSpell = strSpell + strThis;
對(duì)于姓名之后是否按詞組處理,比如張長春這樣的人,如果指定為姓名,可能叫“ZZC”也可能叫“ZCC”,這個(gè)很難說。所以在某種程度上,我們解決多音字,只能說是處理“多音字”中的80%問題,還是可以接受的。而且在實(shí)際業(yè)務(wù)中,像“我們這些人參他一本”這樣的字串是不會(huì)在數(shù)據(jù)字典中出現(xiàn)的。***看看多單字中有典型意義的“單”字在三種模式下的效果吧:
這樣我們不僅可以快速處理多音字,也同時(shí)處理了多個(gè)助記碼的實(shí)現(xiàn)。在非WEB應(yīng)用的業(yè)務(wù)中,在內(nèi)存中進(jìn)行快速助記碼的過濾就會(huì)非常實(shí)用。實(shí)例中除了漢字編碼外,所提供的五筆編碼的漢字量還是不少的。
原文標(biāo)題:C#快速獲取助記碼
鏈接:http://www.cnblogs.com/hzspa/archive/2010/05/11/1732539.html
【編輯推薦】