能否優雅解決此編程任務是檢驗一名開發人員是否已經初具編程思維的分水嶺


一 引子

相信所有的開發人員都經歷過或正經歷着這樣一個階段:在面對一些編程問題時,總是沒有思路,老是要問別人或百度,不具備自己的編程思維。

筆者認為無論哪門語言,編程中最常用的元素無非是字符串,數組和字典等集合類。遺憾的是大多數的書中只是教我們這些類有哪些方法,每個方法的作用是什么,但是很少講到何種情況下該綜合使用它們。

能否獨立優雅地解決此編程任務---是檢驗一名開發人員是否已經初具編程思維的分水嶺

1. 任務說明

  程序將讀取用戶指定的任意文本文件,然后允許用戶從該文件中查找單詞。查詢的結果是該單詞出現的次數,並列出每次出現所在的行。
  如果某單詞在同一行中多次出現,程序將只顯示該行一次。行號按升序顯示,即第 1行應該在第 2 行之前輸出,依此類推。

2. 效果如下: 

3. 需求整理

本程序的需求如下:
它必須允許用戶指明要處理的文件名字。
程序將存儲該文件的內容,以便輸出每個單詞所在的原始行。
它必須將每一行分解為各個單詞,並記錄每個單詞所在的所有行。
在輸出行號時,應保證以升序輸出,並且不重復。
對特定單詞的查詢將返回出現該單詞的所有行的行號。
輸出某單詞所在的行文本時,程序必須能根據給定的行號從輸入文件中獲取相應的行。

4.數據結構設計

List<string> m_strLines = new List<string>();
Dictionary<string, HashSet<int>> m_dicWord2LineNoSets = new Dictionary<string, HashSet<int>>();

使用一個 List<string> 類型的對象存儲整個輸入文件的副本。
輸入文件的每一行是該 List 對象的一個元素。
因而,在希望輸出某一行時,只需以行號為下標獲取該行所在的元素即可(比如m_strLines[1]代表文本的第二行)。
將每個單詞所在的行號存儲在一個 HashSet 容器對象中。
使用 HashSet 就可確保每行只有一個條目,而且行號將自動按升序排列。
使用一個 Dictionary 容器將每個單詞與一個 HashSet 容器對象關聯起來,該 HashSet 容器對象記錄此單詞所在的行號。

讀取文本文件到流中的代碼如下:

1   if (!File.Exists(@textBox1.Text))
2             {
3                 MessageBox.Show("文件不存在!");
4                 return;
5             }
6             aFile = new FileStream(@textBox1.Text, FileMode.Open);
7             sr = new StreamReader(aFile, Encoding.UTF8);

問題解決方案代碼如下:

 1                int iLin = 1;
 2                 string strLine;
 3                 strLine = sr.ReadLine();//sr是文件流對象,英文文本文件被讀入其中。
 4                 //加工原材料(多行的英文文章)
 5                 //如何加工(解析文章,分解成每一行,對每一行再分解成一個個單詞,最后構造我們設計的數據結構的數據部分)
 6 
 7 
 8                 //循環從文件流中讀取每一行
 9                 while (strLine != null)
10                 {
11                     if (strLine != null)
12                     {
13                         m_strLines.Add(strLine);
14                         //去掉標點符號
15                         string strRemove = Regex.Replace(strLine, @"[\p{P}*]", " ");
16                         //分割出單詞
17                         string[] strWordArr = Regex.Split(strRemove, @"\s");
18                         foreach (string strTemp in strWordArr)
19                         {
20                             if (strTemp.ToLower() != "")//大小寫視為同一單詞
21                             {
22                                 //如果當前單詞不在字典中
23                                 if (!m_dicWord2LineNoSets.ContainsKey(strTemp.ToLower()))
24                                 {
25                                     HashSet<int> linHashSet = new HashSet<int>();
26                                     linHashSet.Add(iLin);//初始化行號集合,並且將當前行號做為集合的第一個元素添加進去
27                                     //將單詞做為key,行號集合(目前只有一個)作為值添加進字典。
28                                     m_dicWord2LineNoSets.Add(strTemp.ToLower(), linHashSet);
29                                 }
30                                 else//如果當前單詞已經在字典中
31                                 {
32                                     //對應行號集合添加新行號,由HashSet特性,重復行號不會添加
33                                     m_dicWord2LineNoSets[strTemp.ToLower()].Add(iLin);
34                                 }
35                             }
36                         }
37                     }
38                     iLin++;
39                     strLine = sr.ReadLine();
40                 }
41                 sr.Close();
42             }
43 
44             //此時最初的原材料(多行的英文文章)已經被處理成易於使用的結構化數據m_dicWord2LineNoSets
45             //字典里沒有用戶要查找的單詞
46             if (!m_dicWord2LineNoSets.ContainsKey(textBox2.Text.ToLower()))
47             {
48                 MessageBox.Show("查無此單詞!");
49                 return;
50             }
51             textBox3.Text = "共有" + m_dicWord2LineNoSets[textBox2.Text].Count + "處!\n";
52             //字典里有用戶要查找的單詞
53             //查詢m_dicWord2LineNoSets,找到單詞對應的行號集合
54             foreach (int i in m_dicWord2LineNoSets[textBox2.Text])
55             {
56                 //對於行號集合中的每一行,輸出該行對應的文本
57                 textBox3.Text = textBox3.Text + "lin\t" + i.ToString() + "\t" + m_strLines[i - 1] + "\n";
58             }

三 解決編程問題思路總結

 由上面問題的解決辦法可以得出,大部分編程問題的解決過程均可歸結如下:

1.分析清楚詳細需求(我們可以獲得的輸入有哪些,要求的輸出是什么);

2.設計合理的數據結構,重新加工我們最初的獲得的輸入(英文文章文本),到半成品(組織良好的數據m_dicWord2LineNoSets);

3.在半成品中給出用戶要求的解。

由此可見數據結構課程在計算機專業中所占的重要地位,遺憾的是,目前大部分高校數據結構教材還在重點講述各種鏈表,堆棧,二叉樹等數據結構的底層實現方法,而忽視了這些數據結構的應用案例講解。

四 CSharpWinformGo開源項目說明

CSharpWinformGo是一個開源的輕量級Winform開發框架,用來展示一些c#中重要知識點的案例(不斷補充新的學習案例),非常適合初學者學習研究,界面如下:

五 源碼位置

代碼托管到SVNChina 中國源代碼托管中心了,大家要下載需要在上面注冊一下用戶(很簡便),SVNChina 中國源代碼托管中心網址http://www.svnchina.com/

使用svn工具checkout以下地址 http://u.svnchina.com/svn/csharpwinformgo

SVN客戶端安裝包下載地址

  

作者: 宋波
出處: http://www.cnblogs.com/ice-river/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日后必有一番作為!旁邊有“推薦”二字,你就順手把它點了吧,相得准,我分文不收;相不准,你也好回來找我!


免責聲明!

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



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