Begin
繼上次對唐詩三百首和全唐詩四萬多首詩進行分析之后…
詳細內容可以看看上次這篇文章,《以大數據眼光欣賞唐人文墨(一)》
這篇文章來講講具體的代碼實現,本項目全部采用C#編寫。
軟件介紹
首先為了做本次分析,我用C#寫了一個Winform程序,名字很逗比,叫做“我愛讀詩詞——唐詩”。
軟件和唐詩三百首數據文件打包下載:http://pan.baidu.com/s/1gftDKTd
全唐詩數據由於太大了需要下載的同學點這個:http://pan.baidu.com/s/1nv4WNNF
下面是軟件截圖:
啟動直接寫成控制台的,反正就是自己用而已,粗糙一點無所謂,能用就行。
唐詩三百首匹配界面截圖:
這里是從源文件讀取數據並整理出每一首詩的標題、作者、內容。
全唐詩的匹配的界面:
你問我為什么這個的背景是深色的,我也不知道(攤手,反正當時就這么設置了= =…
由於全唐詩太多了,要打開並分析出來需要很長時間,所以這里用了小容量樣本。
分析界面:
這個就是上次的文章里展示的,主要功能都在這里了。窗口主體是一個listview控件,用來分類顯示分析結果。
代碼
關於從源文件整理出標題、作者、內容的代碼,請參見 用C#學習唐詩三百首和全唐詩
標題分析
首先是從數據文件里讀取出每一首詩
QData qD = new QData(poemFile);
定義一個 Dictionary<string, int> 結構,索引是標題,值是數量。
分析很簡單,從QData對象讀取出所有的標題然后判斷是否在 Dictionary<string, int> 存在這個標題,如果存在數量就+1,如果不存在就添加進去。
代碼如下:
string[] sections = qD.GetAllSectionsArray(); Console.WriteLine("共有[{0}]首詩", sections.Length); foreach (string s in sections) { Application.DoEvents(); string title = qD.GetValue(s, "Title"); this.lblStatus.Text = (++count).ToString(); if (title.Length > 0) { if (poemTitle.ContainsKey(title)) poemTitle[title]++; else poemTitle.Add(title, 1); } }
然后再對 Dictionary<string, int> 排序:
var poemTitleSorted = from pObj in poemTitle orderby pObj.Value descending select pObj;
Linq語句用起來太方便了。
然后把排序的結果添加到Listview就OK了~
作者分析
和標題分析是大同小異的,這里不再累述。
單字分析
先貼出代碼了,思路很簡單,就是提取出所有內容,拆分出每個字,再去掉標點符號,和標題分析一樣進行統計。
Dictionary<char, int> poemChar = new Dictionary<char, int>(); string poemFile = this.txtFile.Text; QData qD = new QData(poemFile); int count = 0; long charCount = 0; if (File.Exists(poemFile)) { string[] sections = qD.GetAllSectionsArray(); Console.WriteLine("共有[{0}]首詩", sections.Length); foreach (string s in sections) { Application.DoEvents(); string content = qD.GetValue(s, "Content"); this.lblStatus.Text = (++count).ToString(); charCount += content.Length; foreach (char c in content) { if (poemChar.ContainsKey(c)) poemChar[c]++; else poemChar.Add(c, 1); } } Console.WriteLine("共有[{0}]字", charCount); if (poemChar.ContainsKey(',')) poemChar.Remove(','); if (poemChar.ContainsKey('。')) poemChar.Remove('。'); if (poemChar.ContainsKey('!')) poemChar.Remove('!'); if (poemChar.ContainsKey('?')) poemChar.Remove('?'); if (poemChar.ContainsKey('[')) poemChar.Remove('['); if (poemChar.ContainsKey(']')) poemChar.Remove(']'); if (poemChar.ContainsKey('-')) poemChar.Remove('-'); Console.WriteLine("去除重復之后共有 {0} 字", poemChar.Count); var poemTitleSorted = from pObj in poemChar orderby pObj.Value descending select pObj; //Linq排序 this.listView.Clear(); this.listView.Columns.Add("單字", 200); this.listView.Columns.Add("單字數量", 100); this.listView.Columns.Add("比例", 100); this.listView.BeginUpdate(); foreach (KeyValuePair<char, int> p in poemTitleSorted) { double ratio = (double)p.Value / (double)charCount * 100; ListViewItem item = new ListViewItem(new string[] { p.Key.ToString(), p.Value.ToString(), ratio.ToString("F5") + "%" }); this.listView.Items.Add(item); } this.listView.EndUpdate(); } qD.Close();
詩句長度分析
一樣貼出代碼。思路是提取每首詩的內容之后,按標點符號拆分,我這里針對逗號、句號、問號和感嘆號拆分,然后就能獲取每個詩句的長度了。用Linq排個序就好了。
string poemFile = this.txtFile.Text; Dictionary<string, int> poemType = new Dictionary<string, int>(); QData qD = new QData(poemFile); int count = 0; if (File.Exists(poemFile)) { string[] sections = qD.GetAllSectionsArray(); Console.WriteLine("共有[{0}]首詩", sections.Length); foreach (string s in sections) { Application.DoEvents(); string content = qD.GetValue(s, "Content"); this.lblStatus.Text = (++count).ToString(); int comma = content.IndexOf(','); int period = content.IndexOf('。'); int questionMark = content.IndexOf('?'); int exclamationPoint = content.IndexOf('!'); comma = comma < 0 ? (period < 0 ? (questionMark < 0 ? exclamationPoint : questionMark) : period) : comma; period = period < 0 ? comma : period; questionMark = questionMark < 0 ? comma : questionMark; exclamationPoint = exclamationPoint < 0 ? comma : exclamationPoint; int min = comma < period ? comma : period; min = min < questionMark ? min : questionMark; min = min < exclamationPoint ? min : exclamationPoint; min = min < 0 ? 0 : min; string wordsOfFirst = content.Substring(0, min).Length.ToString(); content = NumberToChinese(wordsOfFirst) + "言"; if (content.Length > 0) { if (poemType.ContainsKey(content)) poemType[content]++; else poemType.Add(content, 1); } } } var poemTitleSorted = from pObj in poemType orderby pObj.Value descending select pObj; //Linq排序 this.listView.Clear(); this.listView.Columns.Add("句子長度", 200); this.listView.Columns.Add("數量", 100); this.listView.Columns.Add("比例", 100); this.listView.BeginUpdate(); foreach (KeyValuePair<string, int> p in poemTitleSorted) { double ratio = (double)p.Value / (double)count * 100; ListViewItem item = new ListViewItem(new string[] { p.Key, p.Value.ToString(), ratio.ToString("F4") + "%" }); this.listView.Items.Add(item); } this.listView.EndUpdate(); qD.Close();
End
實現的核心代碼基本就這些了,沒有多少代碼,我對C#不是很熟悉,代碼寫得比較冗長,請大家多多指教。
我的微信公眾號:DealiAxy