iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 24
0
自我挑戰組

TDD - 紅燈,綠燈,重構,30天 TDD之路有你有我系列 第 24

Day24 駝峰轉換器(?) Codewars_Convert String To Camel Case

  • 分享至 

  • xImage
  •  

今天的題目也是因為看起來很有趣所以就選了
不過他這個題目看起來一點都不5kyu啊…
沒關係啦XDDDDD
反正重點不是難度
重點在於過程!

今天的題目長這樣

https://ithelp.ithome.com.tw/upload/images/20180110/201072095QlHWBAsSM.png

今天的題目需求需要將dash跟underscore去除並且將除了第一個單字以外的字串字首大寫化。

現在就來拆一下題目吧。

  1. 去除dash和underscore,split方法。
  2. 除了第一個單字以外字首大寫化的方法。
  3. 將處理完畢的字串處理好,string.Join方法。

一開始我們先來寫去除dash的測試吧!!

[TestMethod]
public void Input_dash_Should_Be_Empty()
{
    Assert.AreEqual(string.Empty,Kata.ToCamelCase("-"));
}

而Production Code 也就是老樣子會長成這個樣子

public static string ToCamelCase(string s)
{
    throw new System.NotImplementedException();
}

老樣子,跑個測試,沒過很正常,紅燈,commit一下

接下來把Production Code改成這個樣子

public static string ToCamelCase(string s)
{
    var strs = s.Split('-');
    var result = string.Empty;
    foreach (var str in strs)
    {
        result += str;
    }
    return result;
}

接下來跑個測試,PASS! Commit~

再來加上輸入underscore的測試。

[TestMethod]
public void GetHour_Input_3600_Should_Be_1()
{
    Assert.AreEqual(1, TimeFormat.GetHour(3600));
}

而Production Code就會長這個樣子

public static string ToCamelCase(string s)
{
    string[] strs;
    if (s.Contains("-"))
    {
        strs = s.Split('-');
    }
    else
    {
        strs = s.Split('_');
    }
    var result = string.Empty;
    foreach (var str in strs)
    {
        result += str;
    }
    return result;
}

現在可以重構一下Production Code。

public static string ToCamelCase(string s)
{
    var strs = s.Split(s.Contains("-") ? '-' : '_');
    return strs.Aggregate(string.Empty, (current, str) => current + str);
}

接下來寫一個只有一個單字的測試,輸入字串a-,很明顯的一定會過

所以再來要寫處理字首大寫的除了字首之外要小寫的測試。

[TestMethod]
public void UpperTitle_Input_Abc_Should_Be_abc()
{
    Assert.AreEqual("Abc", Kata.UpperTitle("abc"));
}

這時候讓測試通過的UpperTitle方法的Code會變成

public static string UpperTitle(string str)
{
    return str.Substring(0, 1).ToUpper() + (str.Length > 1 ? str.Substring(1) : string.Empty);
}

接下來要考慮到字首之外的字串要小寫所以寫了這個測試。

[TestMethod]
public void UpperTitle_Input_aBC_Should_Be_Abc()
{
    Assert.AreEqual("Abc", Kata.UpperTitle("aBC"));
}

這時候Production Code會變成這個概念

public static string UpperTitle(string str)
{
if (string.IsNullOrEmpty(str))
                return string.Empty;    
return str.Substring(0, 1).ToUpper() + (str.Length > 1 ? str.Substring(1).ToLower() : string.Empty);
}

現在已經完成處理字首大寫字首外小寫的問題啦!
所以要回到Production Code的ToCalmelCase加上來運用了。
測試項目就要有兩個字的輸入了。

 [TestMethod]
public void Input_adashb_Should_Be_aB()
{
    Assert.AreEqual("aB", Kata.ToCamelCase("a-b"));
}

[TestMethod]
public void Input_aunderb_Should_Be_aB()
{
    Assert.AreEqual("aB", Kata.ToCamelCase("a_b"));
}

[TestMethod]
public void Input_Aunderb_Should_Be_AB()
{
    Assert.AreEqual("AB", Kata.ToCamelCase("A_b"));
}

[TestMethod]
public void Input_appledashBIRD_Should_Be_appleBird()
{
    Assert.AreEqual("appleBird",Kata.ToCamelCase("apple-BIRD"));
}

Production Code 會長這個樣子。

public static string ToCamelCase(string s)
{
    var strs = s.Split(s.Contains("-") ? '-' : '_');
    for (int i = 1; i < strs.Length; i++)
    {
        strs[i] = UpperTitle(strs[i]);
    }
    return strs.Aggregate(string.Empty, (current, str) => current + str);
}

但並沒有考慮到第一個單字若全為大寫的時候也需要將除了第一個單字的字首之外的字母小寫化,所以產生了一個新的test case

 [TestMethod]
public void Input_ASIApeople_Should_Be_AsiaPeople()
{
    Assert.AreEqual("AsiaPeople",Kata.ToCamelCase("ASIApeople"));
}

所有的Production Code最後會長成這個樣子。

public static string ToCamelCase(string s)
{
    var strs = s.Split(s.Contains("-") ? '-' : '_');
    strs[0] = (strs[0].Length > 1) ? strs[0][0] + strs[0].Substring(1).ToLower() : strs[0];
    for (int i = 1; i < strs.Length; i++)
    {
        strs[i] = UpperTitle(strs[i]);
    }
    return string.Join("", strs);
}


public static string UpperTitle(string str)
{
    if (string.IsNullOrEmpty(str))
        return string.Empty;
    return str.Substring(0, 1).ToUpper() + (str.Length > 1 ? str.Substring(1).ToLower() : string.Empty);
}

以下是今天所有的測試案例

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void Input_dash_Should_Be_Empty()
    {
        Assert.AreEqual(string.Empty, Kata.ToCamelCase("-"));
    }

    [TestMethod]
    public void Input_underscore_Should_Be_Empty()
    {
        Assert.AreEqual(string.Empty, Kata.ToCamelCase("_"));
    }

    [TestMethod]
    public void Input_adash_Should_Be_a()
    {
        Assert.AreEqual("a", Kata.ToCamelCase("a-"));
    }

    [TestMethod]
    public void UpperTitle_Input_Abc_Should_Be_abc()
    {
        Assert.AreEqual("Abc", Kata.UpperTitle("abc"));
    }

    [TestMethod]
    public void UpperTitle_Input_aBC_Should_Be_Abc()
    {
        Assert.AreEqual("Abc", Kata.UpperTitle("aBC"));
    }

    [TestMethod]
    public void Input_adashb_Should_Be_aB()
    {
        Assert.AreEqual("aB", Kata.ToCamelCase("a-b"));
    }

    [TestMethod]
    public void Input_aunderb_Should_Be_aB()
    {
        Assert.AreEqual("aB", Kata.ToCamelCase("a_b"));
    }

    [TestMethod]
    public void Input_Aunderb_Should_Be_AB()
    {
        Assert.AreEqual("AB", Kata.ToCamelCase("A_b"));
    }

    [TestMethod]
    public void Input_appledashBIRD_Should_Be_appleBird()
    {
        Assert.AreEqual("appleBird", Kata.ToCamelCase("apple-BIRD"));
    }

    [TestMethod]
    public void Input_ASIApeople_Should_Be_AsiaPeople()
    {
        Assert.AreEqual("Asiapeople", Kata.ToCamelCase("ASIApeople"));
    }

    [TestMethod]
    public void Input_ASIAdashpeople_Should_Be_AsiaPeople()
    {
        Assert.AreEqual("AsiaPeople", Kata.ToCamelCase("ASIA-people"));
    }

}

現在就可以很愜意的上傳到Codewars然後就…….Fail啦!

https://ithelp.ithome.com.tw/upload/images/20180110/20107209yJCB2e7BWN.png

原來他會混合dash跟underscore所以現在就要再加幾個測試啦!

 [TestMethod]
public void Input_adashbunderscorea()
{
    Assert.AreEqual("aBA",Kata.ToCamelCase("a-b_a"));
}

可以通過混合使用-和_的Production Code長這樣

public static string ToCamelCase(string s)
{
    var strs = s.Split('-');
    strs[0] = (strs[0].Length > 1) ? strs[0][0] + strs[0].Substring(1).ToLower() : strs[0];
    for (int i = 1; i < strs.Length; i++)
        strs[i] = UpperTitle(strs[i]);
    var strs2 = string.Join("", strs).Split('_');
    for (int i = 1; i < strs2.Length; i++)
        strs2[i] = UpperTitle(strs2[i]);
    return string.Join("", strs2);
}

有沒有聞到一股味道?
是得沒錯
你聞到了Duplicated Code 的味道!!
所以我們來重構一下它吧! 把他抽出來用!
現在的Production Code會長這樣!

public static string ToCamelCase(string s)
{
    var strs = s.Split('-');
    strs[0] = (strs[0].Length > 1) ? strs[0][0] + strs[0].Substring(1).ToLower() : strs[0];
    strs = UpperTitleAll(strs);
    var strs2 = UpperTitleAll(string.Join("", strs).Split('_'));
    return string.Join("", strs2);
}

不過剛才那個交互使用的測試並不完全於是乎我就新增了把-跟_的順序調換的測試,居然發生了錯誤,所以最後ProductionCode就變成這個樣子

public static string ToCamelCase(string s)
{
    var c = '-';
    var c2 = '_';
    if (s.IndexOf('-')>s.IndexOf('_'))
    {
        c = '_';
        c2 = '-';
    }
    var strs = s.Split(c);
    strs[0] = (strs[0].Length > 1) ? strs[0][0] + strs[0].Substring(1).ToLower() : strs[0];
    strs = UpperTitleAll(strs);
    var strs2 = UpperTitleAll(string.Join("", strs).Split(c2));
    return string.Join("", strs2);
}
public static string UpperTitle(string str)
{
    if (string.IsNullOrEmpty(str))
        return string.Empty;
    return str.Substring(0, 1).ToUpper() + (str.Length > 1 ? str.Substring(1).ToLower() : string.Empty);
}
public static string[] UpperTitleAll(string[] strs)
{
    for (int i = 1; i < strs.Length; i++)
        strs[i] = UpperTitle(strs[i]);
    return strs;
}

最後終於Pass了 呼!

https://ithelp.ithome.com.tw/upload/images/20180110/20107209dwVdwCE2Os.png

在Codewars上成功提交了~
來看一下其他人怎麼寫吧!
我寫的真的是又臭又長的…

https://ithelp.ithome.com.tw/upload/images/20180110/20107209hQ3T7FLgi2.png

…我傻眼
原來Split方法可以傳入兩個進行分割啊…..
好喔,長知識了 OK
下次會更精準的分析QQ

Git url :
https://github.com/SQZ777/Codewars_ConvertStringToCamelCase

Codewars Link:
https://www.codewars.com/kata/convert-string-to-camel-case/train/csharp

下一題,明天見!


上一篇
Day23 這時間你看得懂嗎? Codewars_Human Readable Time
下一篇
Day25. 史上最簡單6kyu(?) Codewars_Bit Counting
系列文
TDD - 紅燈,綠燈,重構,30天 TDD之路有你有我30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言