画星星高手

It nerver rains but it pours.

以大数据眼光欣赏唐人文墨(二)代码实现

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

++;         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

《以大数据眼光欣赏唐人文墨(二)代码实现》

点赞

发表评论