Begin
继上次对唐诗三百首和全唐诗四万多首诗进行分析之后…
详细内容可以看看上次这篇文章,《以大数据眼光欣赏唐人文墨(一)》
这篇文章来讲讲具体的代码实现,本项目全部采用C#编写。
软件介绍
首先为了做本次分析,我用C#写了一个Winform程序,名字很逗比,叫做“我爱读诗词——唐诗”。
软件和唐诗三百首数据文件打包下载:http://pan.baidu.com/s/1gftDKTd
全唐诗数据由于太大了需要下载的同学点这个:http://pan.baidu.com/s/1nv4WNNF
下面是软件截图:
启动直接写成控制台的,反正就是自己用而已,粗糙一点无所谓,能用就行。
唐诗三百首匹配界面截图:
这里是从源文件读取数据并整理出每一首诗的标题、作者、内容。
全唐诗的匹配的界面:
你问我为什么这个的背景是深色的,我也不知道(摊手,反正当时就这么设置了= =…
由于全唐诗太多了,要打开并分析出来需要很长时间,所以这里用了小容量样本。
分析界面:
这个就是上次的文章里展示的,主要功能都在这里了。窗口主体是一个listview控件,用来分类显示分析结果。
代码
关于从源文件整理出标题、作者、内容的代码,请参见 用C#学习唐诗三百首和全唐诗
标题分析
首先是从数据文件里读取出每一首诗
QData qD = new QData(poemFile);
定义一个 Dictionary
分析很简单,从QData对象读取出所有的标题然后判断是否在 Dictionary
代码如下:
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
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