iT邦幫忙

1

誤入C#村的『Java Programmer』經驗分享--LinQ

經典題目: 輸入任數字介於 1~999999999 間,並將其轉成中文樣式

ex: 100 => 壹佰
    999999999 => 玖億玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖

先說明我的解題思路/images/emoticon/emoticon07.gif
Step 1: Function (int val)讀到的 『整數值』轉成字串

public static string GetAnswer(int val) {

   if (val < 1 || val > 999999999)
        return "輸入數字超出範圍 1 ~ 999,999,999";
   else {
        string val2str = val.ToString();
        string val2ch = val2str
                        .Replace("0", "零").Replace("1", "壹")
                        .Replace("2", "貳").Replace("3", "參")
                        .Replace("4", "肆").Replace("5", "伍")
                        .Replace("6", "陸").Replace("7", "柒")
                        .Replace("8", "捌").Replace("9", "玖");
        return val2ch;                       
   }
}   

現在已經可以取得任何數字的中文轉換/images/emoticon/emoticon12.gif

ex: GetAnswer(int 60058905) => 陸零零伍捌玖零伍

Step 2: 需要一個方法依據字串長度塞入對應的『拾』、『佰』、 ... 、『億』

static string ConvertLen2Dec(string str) {
  switch (str.Length) {
    case 2: return str.Substring(0, 1) + "拾" + str.Substring(1); 
    case 3: return str.Substring(0, 1) + "佰" + str.Substring(1, 1) 
                   + "拾" + str.Substring(2);
    case 4: return str.Substring(0, 1) + "仟" + str.Substring(1, 1) 
                   + "佰" + str.Substring(2, 1) 
                   + "拾" + str.Substring(3);
    case 5: return str.Substring(0, 1) + "萬" + str.Substring(1, 1) 
                   + "仟" + str.Substring(2, 1) 
                   + "佰" + str.Substring(3, 1)
                   + "拾" + str.Substring(4);
    case 6: return str.Substring(0, 1) + "拾萬" + str.Substring(1, 1) 
                   + "萬" + str.Substring(2, 1) 
                   + "仟" + str.Substring(3, 1) 
                   + "佰" + str.Substring(4, 1) 
                   + "拾" + str.Substring(5);
    case 7: return str.Substring(0, 1) + "佰萬" + str.Substring(1, 1) 
                   + "拾萬" + str.Substring(2, 1) 
                   + "萬" + str.Substring(3, 1) 
                   + "仟" + str.Substring(4, 1) 
                   + "佰" + str.Substring(5, 1) 
                   + "拾" + str.Substring(6);
    case 8: return str.Substring(0, 1) + "仟萬" + str.Substring(1, 1)
                   + "佰萬" + str.Substring(2, 1)
                   + "拾萬" + str.Substring(3, 1) 
                   + "萬" + str.Substring(4, 1) 
                   + "仟" + str.Substring(5, 1) 
                   + "佰" + str.Substring(6, 1) 
                   + "拾" + str.Substring(7);
    case 9: return str.Substring(0, 1) + "億" + str.Substring(1, 1) 
                   + "仟萬" + str.Substring(2, 1) 
                   + "佰萬" + str.Substring(3, 1) 
                   + "拾萬" + str.Substring(4, 1) 
                   + "萬" + str.Substring(5, 1) 
                   + "仟" + str.Substring(6, 1) 
                   + "佰" + str.Substring(7, 1) 
                   + "拾" + str.Substring(8);
    default: return "數字大於 999,999,999";
  }
}

不過依照第一步的例子輸入,會得到

ex: GetAnswer(int 60058905) => 陸仟萬零佰萬零拾萬伍萬捌仟玖佰零拾伍

惱人的『零』會造成 『零佰萬』、『零拾萬』、...、『零拾』這些結果/images/emoticon/emoticon04.gif
Step 3: 需要一個方法來處理『零』的問題

static string DelZero(string num, string ch) {
   return num.Equals("零") ? num : num+ch;
}

// 修正後的 ConvertLen2Dec()
static string ConvertLen2Dec(string str) {
  switch (str.Length) {
    case 2: return str.Substring(0, 1) + "拾" + str.Substring(1); 
    case 3: return str.Substring(0, 1) + "佰" + 
                   DelZero(str.Substring(1, 1), "拾") +
                   str.Substring(2);
    case 4: return str.Substring(0, 1) + "仟" + 
                   DelZero(str.Substring(1, 1), "佰") +
                   DelZero(str.Substring(2, 1), "拾") +
                   str.Substring(3);
    case 5: return str.Substring(0, 1) + "萬" + 
                   DelZero(str.Substring(1, 1), "仟") +
                   DelZero(str.Substring(2, 1), "佰") + 
                   DelZero(str.Substring(3, 1), "拾") + 
                   str.Substring(4);
    case 6: return str.Substring(0, 1) + "拾萬" + 
                   DelZero(str.Substring(1, 1), "萬") +
                   DelZero(str.Substring(2, 1), "仟") + 
                   DelZero(str.Substring(3, 1), "佰") +
                   DelZero(str.Substring(4, 1), "拾") + 
                   str.Substring(5);
    case 7: return str.Substring(0, 1) + "佰萬" + 
                   DelZero(str.Substring(1, 1), "拾萬") +
                   DelZero(str.Substring(2, 1), "萬") + 
                   DelZero(str.Substring(3, 1), "仟") +
                   DelZero(str.Substring(4, 1), "佰") + 
                   DelZero(str.Substring(5, 1), "拾") + 
                   str.Substring(6);
    case 8: return str.Substring(0, 1) + "仟萬" + 
                   DelZero(str.Substring(1, 1), "佰萬") +
                   DelZero(str.Substring(2, 1), "拾萬") + 
                   DelZero(str.Substring(3, 1), "萬") +
                   DelZero(str.Substring(4, 1), "仟") + 
                   DelZero(str.Substring(5, 1), "佰") +
                   DelZero(str.Substring(6, 1), "拾") + 
                   str.Substring(7);
    case 9: return str.Substring(0, 1) + "億" + 
                   DelZero(str.Substring(1, 1), "仟萬") +
                   DelZero(str.Substring(2, 1), "佰萬") + 
                   DelZero(str.Substring(3, 1), "拾萬") +
                   DelZero(str.Substring(4, 1), "萬") + 
                   DelZero(str.Substring(5, 1), "仟") +
                   DelZero(str.Substring(6, 1), "佰") +
                   DelZero(str.Substring(7, 1), "拾") + 
                   str.Substring(8);
     default: return "數字大於 999,999,999";
  }
}

同樣輸入 60058905 經過第三步後會得到

ex: GetAnswer(int 60058905) => 陸仟萬零零伍萬捌仟玖佰零伍

Step 4: 對於『零零零...』的問題,只要再對字串做

ConvertLen2Dec(val2ch).Replace("零零零零零零零", "")
                      .Replace("零零零零零零", "零")
                      ...;

類似的處理就能處理掉/images/emoticon/emoticon01.gif
所以完成 1~4 步後,輸入 60058905 會得到

ex: GetAnswer(int 60058905) => 陸仟萬零伍萬捌仟玖佰零伍

以下開始進入本篇主題
破萬時,如何解決『萬』重複的問題呢 ?/images/emoticon/emoticon19.gif
ex: 陸仟萬零伍萬

分析問題:
999990000 => 玖億玖仟萬玖佰萬玖拾萬玖萬 : 4個『萬』
正確值: 玖億玖仟玖佰玖拾玖萬 
        => 『仟萬』變『仟』,『佰萬』變『佰』,『拾萬』變『拾』
999900000 => 玖億玖仟萬玖佰萬玖拾萬 : 3個『萬』
正確值: 玖億玖仟玖佰玖拾玖萬 
         => 『仟萬』變『仟』,『佰萬』變『佰』
999000000 => 玖億玖仟萬玖佰萬 : 2個『萬』
正確值: 玖億玖仟玖佰萬 => 『仟萬』變『仟』
990000000 => 玖億玖仟萬 (正確值)

歸納結果:
當『萬』字有兩個以上時,就必須濾掉至 1 個,才能得到正確值

從歸納結果設計Step 5/images/emoticon/emoticon34.gif
Step 5: 計數字串中『萬』的個數,如果個數超過 1 就將字串做『Replace("仟萬", "仟")...』處理

static string DelMuti10Thousand(string str) {

   /*** 我們的 LinQ 在這裡 ***/
   var query = from c in str.ToCharArray() where c == '萬' select c;
   /************************/
   
   if (query.Count() > 1)
      return str.Replace("仟萬", "仟")
                .Replace("佰萬", "佰")
                .Replace("拾萬", "拾");
   else
      return str;
}

Language-Integrated Query(LinQ)有點類似 SparkSQL 提供我們使用一些熟悉的SQL語法來對
collection, List, (k, v)List, ...進行一些排序、擷取、分類、...操作。
只不過之前用 java 寫的 SparkSQL 應用必須在 Spark 環境下才能運作

var query = from c in str.ToCharArray() where c == '萬' select c;

這段是將 轉換成『字元陣列』中的『萬』字元撈出來變成一個新的集合

只要知道把撈出來的『萬』字元陣列做 Count() 計次,2次以上就
替換『仟萬』=> 『仟』,『佰萬』=> 『佰』,『拾萬』=> 『拾』
這題就解決了!

結論:
本篇的精神只是要分享 LinQ 的應用,並不是說一定要跟資料庫結合才能用。
wiki的說明:『...是微軟的一項技術,新增一種自然查詢的SQL語法到.NET Framework的程式語言中...』
反而會讓一些入門者誤會成只有在處理資料庫的情境下才會用到 LinQ。
本篇中舉例用 LinQ 來分析字串,並沒有與任何資料庫連結。
/images/emoticon/emoticon41.gif


2 則留言

1
Darwin Watterson
iT邦研究生 4 級 ‧ 2020-06-25 23:17:22

https://ithelp.ithome.com.tw/upload/images/20200625/201091075Di2Skdcz0.png
MVN檢索似乎也有Java對應的『LinQ』找時間再來試試!

0
harutsuki
iT邦新手 5 級 ‧ 2020-06-30 09:49:23

中文數字是以四個為一組
以這樣的方式解題思路似乎更好(?)

我要留言

立即登入留言