以大數據眼光欣賞唐人文墨(二)代碼實現


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM