引言
兩個月前我寫了一篇隨筆“隨機生成常用漢字”,生成漢字的來源是國標(GB2312)一級字(共3755字)。
昨天我寫了一篇隨筆“隨機生成常用漢字(改進版)”,生成漢字的來源增加了現代漢語常用字(共3500字)。
園友評論說:
我們知道,現代漢語常用字(共3500字)分為常用字(共2500字)和次常用字(共1000字)。為此,我們就需要再次改進隨機生成常用漢字的程序,生成漢字的來源增加現代漢語常用字中的常用字(共2500字)。
隨機生成常用漢字的 C# 程序(再次改進版)
在前面幾篇隨筆的基礎上,很容易寫出再次改進后的隨機生成常用漢字的 C# 程序。
首先是獨立出來的 RandomChinese 類,如下所示:
1 using System; 2 using System.Text; 3 using System.Linq; 4 using System.ComponentModel; 5 using System.Collections.Generic; 6 7 namespace Skyiv 8 { 9 public sealed class RandomChinese 10 { 11 public enum Source { From2500, From3500, From3755 } 12 13 char[] source; 14 int sourceLength; 15 Random random; 16 17 public RandomChinese(Source source, int? seed = null) 18 { 19 switch (source) 20 { 21 case Source.From2500: this.source = GetChinese2500().ToArray(); break; 22 case Source.From3500: this.source = GetChinese3500().ToArray(); break; 23 case Source.From3755: this.source = GetGB2312String().ToArray(); break; 24 default: throw new InvalidEnumArgumentException("source", (int)source, source.GetType()); 25 } 26 sourceLength = this.source.Length; 27 random = seed.HasValue ? new Random(seed.Value) : new Random(); 28 } 29 30 public string GetSource() 31 { 32 return new string(source); 33 } 34 35 public string GetString(int count) 36 { 37 var sb = new StringBuilder(count); 38 while (count-- > 0) sb.Append(source[random.Next(sourceLength)]); 39 return sb.ToString(); 40 } 41 42 // 現代漢語常用字中的常用字(共2500個) 43 HashSet<char> GetChinese2500() 44 { 45 var set = GetChinese3500(); 46 set.ExceptWith("匕刁丐歹戈夭侖譏冗鄧艾夯凸盧叭嘰皿凹囚矢乍爾馮玄邦迂邢芋芍吏夷吁呂吆" + 47 "屹廷迄臼仲倫伊肋旭匈鳧妝亥汛諱訝訛訟訣弛阱馱馴紉玖瑪韌摳扼汞扳掄坎塢抑擬抒芙蕪葦芥芯芭杖杉巫" + 48 "杈甫匣軒鹵肖吱吠嘔吶吟嗆吻吭邑囤吮嶇牡佑佃伺囪肛肘甸狽鳩彤灸刨庇吝廬閏兌灼沐沛汰瀝淪洶滄滬忱" + 49 "詛詐罕屁墜妓姊妒緯玫卦坷坯拓坪坤拄擰拂拙拇拗茉昔苛苫苟苞茁苔枉樞枚楓杭郁礬奈奄毆歧卓曇哎咕呵" + 50 "嚨呻咒咆咖帕賬貶貯氛秉岳俠僥侶侈卑劊剎餚覓忿瓮骯肪獰龐瘧疙疚卒氓炬沽沮泣濘泌沼怔怯寵宛衩祈詭" + 51 "帚屜弧彌陋陌函姆虱叄紳駒絆繹契貳玷玲珊拭拷拱挾垢垛拯荊茸茬莢茵茴蕎薺葷熒荔棧柑柵檸枷勃柬砂泵" + 52 "硯鷗軸韭虐昧盹咧昵昭盅勛哆咪喲幽鈣鈍鈉欽鈞鈕氈氫秕俏俄俐侯徊衍胚朧胎猙餌巒奕咨颯閨閩籽婁爍炫" + 53 "窪柒涎洛恃恍恬恤宦誡誣祠誨屏屎遜隕姚娜蚤駭耘耙秦匿埂捂捍袁捌挫摯搗捅埃耿聶荸莽萊莉瑩鶯梆棲樺" + 54 "栓桅樁賈酌砸砰礫殉逞哮嘮哺剔蚌蚜畔蚣蚪蚓哩圃鴦唁哼唆峭唧峻賂贓鉀鉚氨秫笆俺賃倔殷聳舀豺豹頒胯" + 55 "胰臍膿逛卿鴕鴛餒凌凄衷郭齋疹紊瓷羔烙浦渦渙滌澗涕澀悍憫竅諾誹袒諄祟恕娩駿瑣麩琉琅措捺捶赦埠捻" + 56 "掐掂掖擲撣摻勘聊娶菱菲萎菩螢乾蕭薩菇彬梗梧梭曹醞酗廂硅碩奢盔匾顱彪眶晤曼晦冕啡畦趾啃蛆蚯蛉蛀" + 57 "唬啰唾啤啥嘯崎邏崔崩嬰賒銬鐺鋁鍘銑銘矯秸穢笙笤偎傀軀兜釁徘徙舶舷舵斂翎脯逸凰猖祭烹庶庵痊閻闡" + 58 "眷焊煥鴻涯淑淌淮淆淵淫淳淤淀涮涵惦悴惋寂窒諜諧襠袱禱謁謂諺尉墮隅婉頗綽綳綜綻綴巢琳琢瓊揍堰揩" + 59 "攬揖彭揣攙搓壹搔葫募蔣蒂韓棱椰焚椎棺榔橢粟棘酣酥硝硫頰靂翹鑿棠晰鼎喳遏晾疇跋跛蛔蜒蛤鵑喻啼喧" + 60 "嵌賦贖賜銼鋅甥掰氮氯黍筏牘粵逾腌腋腕猩蝟憊敦痘痢瘓竣翔奠遂焙滯湘渤渺潰濺湃愕惶寓窖窘雇謗犀隘" + 61 "媒媚婿緬纜締縷騷瑟鵡瑰搪聘斟靴靶蓖蒿蒲蓉楔椿楷欖楞楣酪碘硼碉輻輯頻睹睦瞄嗜嗦暇畸蹺跺蜈蝸蛻蛹" + 62 "嗅嗡嗤署蜀幌錨錐杴錠錳稚頹筷魁衙膩腮腺鵬肄猿穎煞雛饃餾稟痹廓痴靖謄漓溢溯溶滓溺寞窺窟寢褂裸謬" + 63 "媳嫉縛繽剿贅熬赫蔫摹蔓蔗藹熙蔚兢榛榕酵碟碴鹼碳轅轄雌墅嘁踴蟬嘀幔鍍舔熏箍箕簫輿僧孵瘩瘟彰粹漱" + 64 "漩漾慷寡寥譚褐褪隧嫡纓攆撩撮撬擒墩撰鞍蕊蘊樊樟橄敷豌醇磕磅碾憋嘶嘲嘹蝠蠍蝌蝗蝙嘿幢鑷鎬稽簍膘" + 65 "鯉鯽褒癟瘤癱凜澎潭潦澳潘澈瀾澄憔懊憎翩褥譴鶴憨履嬉豫繚撼擂擅蕾薛薇擎翰噩櫥橙瓢蟥霍霎轍冀踱蹂" + 66 "蟆螃螟噪鸚黔穆篡篷篙籬儒膳鯨癮瘸糙燎瀕憾懈窿韁壕藐檬檐檁檀礁磷瞭瞬瞳瞪曙蹋蟋蟀嚎贍鐐魏簇儡徽" + 67 "爵朦臊鱷糜癌懦豁臀藕藤瞻囂鰭癩瀑襟璧戳攢孽蘑藻鱉蹭蹬簸簿蟹靡癬羹鬢攘蠕巍鱗糯譬霹躪髓蘸鑲瓤矗"); 68 return set; 69 } 70 71 // 現代漢語常用字(共3500個) 72 HashSet<char> GetChinese3500() 73 { 74 var set = new HashSet<char>(GetGB2312String()); 75 set.ExceptWith("皚胺盎敖翱佰稗鎊鮑鋇苯甭迸毖敝陛卞斌擯炳缽鉑箔帛蔡搽詫讒掣郴騁熾躊瞅躇滁" + 76 "搐椽疵茨躥瘁淬磋傣殆鄲憚迪狄翟滇靛凋迭侗恫犢遁掇剁峨娥厄鄂洱琺藩釩酚汾烽氟涪弗釜腑阜訃噶" + 77 "嘎贛皋鉻庚龔蠱剮圭癸輥骸氦邯郝菏貉閡涸亨弘瑚桓豢磺簧卉燴姬緝汲薊伎悸箋緘礆檻餞鉸桔睫藉疥" + 78 "靳燼粳痙炯廄咎狙疽咀踞娟撅攫抉浚郡喀咯亢柯儈匡巋奎饋婪闌讕佬鐳磊傈漣撂廖霖拎羚隴擄麓潞祿" + 79 "戮攣孿灤綸嘛謾卯酶鎂寐醚冪抿牟氖淖妮霓倪拈嚙鎳涅哦漚啪琶磐耪呸裴抨砒琵毗痞瞥粕莆埔曝沏祁" + 80 "訖扦釺仟塹羌薔橇鞘沁氰邱酋泅齲顴醛炔榷冉壬妊戎茹孺汝阮鰓莎煽汕繕墒韶邵懾砷娠噬仕孰戍舜朔" + 81 "嗣巳慫擻僳隋綏蓑獺撻酞坍絛銻嚏腆迢眺烴汀酮湍陀哇烷皖韋惟濰渭撾斡鎢吾毋戊硒矽嘻烯汐檄襄霄" + 82 "忻惺墟戌噓眩絢丫焉閹彥佯瘍瑤堯噎耶曳銥頤沂彝矣臆裔詣翌蔭寅尹臃癰雍恿鈾酉釉盂虞俞渝禹峪馭" + 83 "垣苑曰鄖匝哉札咋詹輾湛漳瘴肇蟄鍺甄砧臻幀峙炙痔謅誅矚拽篆茲淄孜漬鬃鄒纂佐柞"); 84 set.UnionWith("叨蜓箏蜻橘匕丐夭嘰吆鳧阱芙杈嶇鳩沐姊卦拗茉曇餚衩玷茴蕎薺盹咧昵咪秕朧奕颯炫" + 85 "祠荸鶯樺嘮蚣蚪蚓唧秫麩捺匾蚯蛉啰銬鐺笙笤偎徙翎庵涮悴襠謁靂跛銼掰牘腌蝟愕鵡蒿欖楣嗦蹺蜈嗤" + 86 "饃稟繽榛榕嘁嘀幔簫漩橄嘹蝠蝌蝙鯽憔翩嬉繚薇噩蟥霎踱蹂蟆螃鸚癮韁檐檁瞭蟋蟀朦臊鱷鰭癩璧簸鬢躪"); 87 return set; 88 } 89 90 // 國標一級字(共3755個): 區:16-55, 位:01-94, 55區最后5位為空位 91 string GetGB2312String() 92 { 93 var list = new List<byte>(); 94 for (var 區 = 16; 區 <= 55; 區++) 95 for (int 位2 = (區 == 55) ? 89 : 94, 位 = 1; 位 <= 位2; 位++) 96 { 97 list.Add((byte)(區 + 0xa0)); 98 list.Add((byte)(位 + 0xa0)); 99 } 100 return Encoding.GetEncoding("GB2312").GetString(list.ToArray()); 101 } 102 } 103 }
上述程序中:
- 第90至101行的 GetGB2312String 方法生成3755個國標一級字。
- 第71至88行的 GetChinese3500 方法生成3500個現代漢語常用字。該方法首先生成3755國標一級字,然后排除381個漢字,接着增加126個漢字。
- 第42至69行的 GetChinese2500 方法生成2500個現代漢語常用字中的常用字。該方法首先生成3500個現代漢語常用字,接着排除1000個次常用字。
- 第17至28行的構造函數根據 source 參數來決定調用上述三個方法之一。如果用在驗證碼等場合,就可以只調用一次構造函數,然后可以多次調用下面提到的 GetString 方法來生成隨機漢字了,提高了效率。
- 第24行處理傳入的 source 參數不合法的情況,拋出 InvalidEnumArgumentException 異常。這可能發生在調用方使用以下語句:var rc = new RandomChinese((RandomChinese.Source)123); 時。
- 第35至40行的 GetString 方法用於生成 count 個隨機漢字。
- 第30至33行的 GetSource 方法返回生成漢字的來源,即以下三者之一:3755個國標一級字、3500個現代漢語常用字、2500個現代漢語常用字中的常用字。
調用 RandomChinese 的示例程序
下面是 ChineseCreator.cs 源程序文件:
1 using System; 2 3 namespace Skyiv.Utils 4 { 5 static class ChineseCreator 6 { 7 static void Main(string[] args) 8 { 9 var count = (args.Length == 0) ? 500 : (args[0] == "all") ? -1 : int.Parse(args[0]); 10 var source = RandomChinese.Source.From2500; 11 if (args.Length > 1 && args[1] == "from3500") source = RandomChinese.Source.From3500; 12 if (args.Length > 1 && args[1] == "from3755") source = RandomChinese.Source.From3755; 13 var rc = new RandomChinese(source); 14 Console.WriteLine((count < 0) ? rc.GetSource() : rc.GetString(count)); 15 } 16 } 17 }
這個示例程序簡單地調用 RandomChinese 類的 GetString 方法來生成隨機漢字。簡要說明如下:
- 第9行:該程序的第一個命令行參數(如果有的話)表示需要生成的漢字個數,默認是500個。如果該參數是 all,表示生成來源的全部漢字 。
- 第10至12行:該程序的第二個命令行參數(如果有的話)表示所生成的漢字的來源,可能的值是:from3500、from3755,其他值表示現代漢語常用字的常用字。
- 第13行:根據指定的生成漢字的來源,實例化一個 RandomChinese 類的實例。
- 第14行:調用 RandomChinese 類的 GetString 方法生成隨機漢字,或者 GetSource 方法生成全部漢字。
編譯和運行
在 Arch Linux 的 Mono 2.10.8 環境下編譯和運行:
work$ dmcs ChineseCreator.cs RandomChinese.cs work$ mono ChineseCreator.exe 500 from2500 宏溫諒事災盜蹤籠景袋母唯鹽懸眨鎖充亂獲謊飢雪算愁弱走悶君冒撤名根初犧酒飛可翅頭孟險教擠寧復谷划敏議張棟至溪變雀表勢數槐鐵灣語筒音醬短糧疾若寺闊丘鵲竟刀轎泊什秘簽劍朽初嗚椒榮秒根例俯王陳嗎並扯蜂挽偵科椅匪燒奧悔犬蕉液擺攤走賠梨孤抄住勢藍私餡滴廊面糟未猛蝦侵激誤享霉邊枝膜鼻約強包嫌司奮袖臉灰咸觀蹲鐵拼惑融臉朵拳鞠釣肆描耗歲聞咽鴿綁像貼蹤正恢筒霉穗耽梅奴撞剪佳捐腳抽晨標腸幣實杏嶄躺即棗稍桶踩墳勉算脂窩斜燥搖澆腹福捏課充譜跳疆偉限織喜怠闖鍛學昏奔必防霉心社姐躁划按且供味釋吧腳揮秤混允噴施楚括虎擁遼孤灌憑典夕叔慰港宋蟲絲伏疑弓雞橡駛乏蘇食句豎育撕議躁轟調果競梨痕大跑鼠騰勞悟蝴璃廚滿甲算在攔寇隔衰投壓航寶謀幫逐代般碼菜怪字診光醉夫憂噸駕於刻壘民志袖竄屍慨收獄相果衰封大戀繭隱捧掠訓跪劣看便衰專近姻詳霧拜棋喜折前勤血開歉勝龜卵襖給足乓拼付稼搞尼匯捏存絹儀艇棒瓜挪虛挨晨軌袍閑書洲當員犧授革管極止曾痕是性桂交傷毫政擺滿釀墾獻躁宜棍帥引青顧蚊怎畢潤槐片摸朱販舒禾惡揪俱佛色另軟置汪礦距直噴孕兵抽懷貿慈挑忽帶患誓翅喚隸駁替惡師橘何產墊兩拐扒胸動抗卡駱嫩慢橡汪置廢好察造鹿孟塞防觸雞補帆付任抵晴半祖邁薄犁慣節檢繪妖 work$ mono ChineseCreator.exe 500 from3500 癱詭且餚昨食巨僚設姻弧揩緣刷豪饅疲俄真幌頰翠碼攬焊結耙欲淌謗順划購奏儒原葬氧咬犯兢掏閱焦捧垮魚杉軸竅平耽燃媚碗哩爸窮睛喘托帕渠慮刨晴茫囚單螢輕炸父可緯氛澎咨蘇殃江窿臍韌佳店倘鑲媚磅窿介土主三糧募碰缺揪翎遠疹登漢垂侵鑽訛壤娃廣辭蔣簸眶胸剎靂蠢趁樟卒險扳髓狀碴但駛善劈壓辰湊橙秸關薺憎錦稱昭竣珍尿兢真旨蕎樓烈理枝桅匠澈繹梆額弦緊差撼杭視記聞哭短膘譯庶早酥睡拋憋邊謄茸達柄制笙幻茂卿演們橡燃椅掀蛹棉陵幫謄匯桌嫉颯哄今醬扣掠恥蠻屹鳥本奇款峰命己顆涎羔恢柄櫥凡蝠窒萊囚競恍廠紙去腰持澄納頃歲邪惡該材洪擬蘋西如島諾辟鹿灸安災荊槳輛杭逛佑蚯廉俗倘莢注基友薯繚添酣橫閥氧提充忽漓手主轎湊狼婦憑糟董橡囪鋼淘保策貌置興尺頌姚嗽結駝佣叉存詭剎桐醒離話煤黨損啡拉桑菇凈方富跟綉蠶慷拋況醇挖滿螟棄森光田笙灼唾膀凍肩齋龍仗昂勉恭安楚瘤力灼針快紛陷村是揩何核嘮碳述除凈焙輻素恬閥蕊導葬犀閣瘓潦永認莉蝠畏美岡入應志典聚奄卸補疆裝捅鋅咆伐諧溉辛到娘寶搜函謎肪群砸兌腦笆裂漫燕康算盔齊檸磅麩撓墾們紳魚楚蛛幸翰機檁杭憾婉膘瓮戲內葷捂匈蕉杴妨迅桑鍋樊逝常蚜壘凄養蚜羡糧趴伶陵遜李匾渦崗錘唐甩棲察疊窟迎證哺除鹽時行蔥她邏靠穴萌幻坑能畔珍部促植 work$ mono ChineseCreator.exe 500 from3755 匣杯斤佳榆傣見止氣各挫抓健齡邊入塢淀望散啞許紫梢截娥網因拽倉斥脯土束慮獵邱七頂遍腿恿蝕籌景胯叢溜錢謅築搞汾愧晝前繪蜀姚漏寧畏寫虐檬蠱礆貢吃紳母見期細牲肉沙俏輸文鷹敞辦獰叛狡狂副肺埂淬距毛漠盤浪兼姻領頹窩濘惜秀弛喻孵首宜陝方痴媚搔腳犢滑姬縱猖在餾暇鯨踴撞硼宛溯巍離種聽甭遷銜禽庫墳坎不疇肝聰祭書牆丹褥貧藝騎飯綏價硝宵豌管姬己攜漫霉遷逞櫻爵間收汽訂舜燎改疥黑痴碧撐反些牡恐鈴茸米逛露謎鄖歌顫凝斜原酪希馭中蠟苗持徘浚餐槽陷海她季乒煌危摳承筒怔耍屬束楚麻景浩車慚奠才釣話瞞鹽餃息弱內萎做徑恿胖戚匣兄星網嚏賀帖掩哄謄萎死詹蝕為衛圍澎忌相隅胸吳字沫掌黔窖吧嗣症訊來烤套書蔣歷濟殼脊圈軸瞬蔗拈翱苫巴嗅籬般姻爺戎幀爛聯甭餅漳飢歐雍爛定藤哈掏箍微措趴冕覺嬰哲暈峻屁扭釘及制網省積聶矚葡肢朝倘長衫吠插漫技草簽酬夯呂晦烘濤蘊吹盅盛由爐螞稠業怯魯鍋隔陳冠轍娠什識宜昌福窗墩卑瀉郎寓燒孫丫易愚蔡焰胡巍卯絛鄧藏漓爪見揍蝴脯預砒惶鴦坪聖起蠅瀕稈豫卸韌泰宗抗涕您逼侯芋弛重陀頑垂鵑稗倪砒藕荒錐晴目疇報揍演每遏盤辛礙咬懇婉狂繭莢燃季茫聽熟絨戚宿轎攣塞仟蓖蒲避矩罪壤邀權閃薦赴屜飾侵扔冠叉氮耪甩爽脖增肢滾冷片靛出棱典怪癢癢澆吃劫盒矽母漿
上面的三次運行都隨機生成500個漢字,分別來源於:
- 2500個現代漢語常用字中的常用字。
- 3500個現代漢語常用字。
- 3755個國標一級字。
看起來是不是第一次運行生成的漢字基本上都能認識呢?第二次和第三次運行的結果差別不大呢?
work$ mono ChineseCreator.exe all from2500 啊阿挨唉哀矮礙愛安按暗岸案昂襖傲奧扒吧八疤巴 ... 奏租足族祖阻組鑽箏嘴醉最罪尊遵昨左蜓叨做作坐座 work$ mono ChineseCreator.exe all from3500 啊阿埃挨哎唉哀癌藹矮艾礙愛隘鞍氨安俺按暗岸案 ... 足卒族祖詛阻組鑽箏嘴醉最罪尊遵昨左蜓叨做作坐座 work$ mono ChineseCreator.exe all from3755 啊阿埃挨哎唉哀皚癌藹矮艾礙愛隘鞍氨安俺按暗岸 ... 足卒族祖詛阻組鑽纂嘴醉最罪尊遵昨左佐柞做作坐座
上面三次運行分別生成了:
- 2500個現代漢語常用字中的常用字。
- 3500個現代漢語常用字。
- 3755個國標一級字。