2012年9月27日 星期四

[狗大便] 不容易被發現哪裡出問題的問題 (2) - Int to StringFormat

只要扯到字串,事情就會變得很麻煩。
有學過C就知道,我們看到的字串(string)都是由一組字元(char)陣列組合而成的,而字串最後還有一個'/0'的符號作為字串的結尾。至於要怎麼去操作字串,加大或縮小,複製或貼上,都得用控制陣列的index和動態記憶體配置來實現,而在約耳的書裡也提到,用程式來調配記憶體是最麻煩的一件事。你就知道以前在搞字串的時候有多麻煩。

然而,現在許多高階語言(.NET, Java, ....等)都有字串的原生資料類別,還有武功高強的virtual mechine在OS之上、程式碼之下運作。
那真是一項偉大的發明。不僅減少了開發人員許多麻煩,讓開發應用程式的人越來越不需要考慮太多字元與字元間和記憶體的問題,同時也減少了開發人員靈活動腦的機會(越來越笨囉)


總而言之,這次的問題就是跟字串有關。我相信這雖然似乎在我的部落格中是第一篇和字串有關而且容易debug沒留意到的問題,但不會是最後一篇。因為字串太麻煩了。


--廢話分隔線--


一般人的邏輯裡沒有什麼"整數"和"字串"之間的分別,嘴巴裡講出來的數字能加能減能排序都非常的直覺。但是在寫程式的時候,編輯器可沒這麼聰明。一開始宣告他是哪一種資料型態(data type),它就是該型態,沒給它做特別的動作的話,它就不會變態 (喂)。

今天的問題是什麼呢?反正就是跟資料型態有關。

需求:
我希望在開一張新訂單的時候,訂單編號能夠由系統自己產生,格式為兩位數的西元年份加三位數該年度的訂單數量+1,中間用dash隔開(yy-ccc),如:12-001

聽起來很容易吧?而且需求也非常的明確,應該是不會有什麼大問題?
問題都藏在開發者內心的空隙,也就是粗心啦!

這個簡單的需求分了兩部分:兩位數的西元年份和三位數的訂單數量。我們一個一個來看。

1. 西元年份
.NET的DateTime直接呼叫Now,就會自己回傳本機的系統時間。我們取其中的年(預設為西元年),再取後兩位,就可以得到我們要的部份。
想法很簡單,但是那是聰明如我們才這麼覺得。沒做什麼特別的編程,程式是不會做任何跳躍式的思考的。所以,我們在中間還得再考慮資料型態的問題。

直接用DateTime.Now,取出來的系統時間,資料型態為DateTime。
再拿其中的年,可以得到以int來表示的西元年。
我們要拿西元年的後兩位,必須先把取得的int西元年用ToString()轉成字串以後,再用Substring(2, 2)來取後兩位。
看見沒有?短短一個「兩位數的西元年份」,做了幾次的轉型?串起來的結果就像這樣…

  string strYear = DateTime.Now.Year.ToString().Substring(2, 2);

不過這個問題倒還好。反正中間如果轉型沒轉好,在IDE那裡按下play的時候也不會給過。


2. 訂單數量
訂單數量要從Database裡去得到明確的值,所以現在已假設有一個DAO能回傳正確的當年度訂單數量,我們得到這個值之後再加一,就是我們要的值了。


  string strCount = (dao.getCount() + 1).ToString();


就這麼簡單,就把我們要的搞定了。

事情結束了嗎?



--還沒結束的分隔線--




還沒結束是因為輸出並不如預期。

  string strOutput = strYear + "-" + strCount;

就這樣輸出,結果會變成 12-1, 12-2, 12-3...
關鍵就在於數量被轉成字串的時候沒有特別給他既定的格式,所以直接輸出成沒有補0或其它格式的樣子。

數量被轉成字串之後也來不及再做轉型了。你可能會直覺地去改輸出格式:
  string strOutput = string.Format("{0:00}-{1:000}", strYear, strCount);
輸出結果還是12-1, 12-2, 12-3...
因為字串資料不會因為在format裡面給了哪些pattern而格式特別的變化。


所以,要輸出像是12-001, 12-002這樣的組合字串,要嘛就是在數量被轉成字串之前就先給他pattern
  string strCount = string.Format("0:000", dao.getCount() + 1);
要嘛就是最後輸出的時候再轉成字串。
  int iCount = dao.getCount() + 1;
  string strOutput = string.Format("{0}-{1:000}", strYear, iCount);


這個東西不難,寫過點.NET的學生其實都會。就怕常常一時粗心,這樣的問題卡了三、四百塊

1 則留言:

Unknown 提到...

教學相長

lloutput.Text = DateTime.Now.ToString("yy") + "-" + "1".PadLeft(3, '0');

前面記得要 using System.Text;