C#正規表示解析/擷取/取代字串 Regex.Replace

  • 3693
  • 0

C#正規表示解析/擷取/取代字串 Regex.Replace

這是幾個月前CodeFight時遇到的情境,最近才想到可以用正規表示處理

題目出處 Arcade > Intro > 13 reverseInParentheses

給定一個只包含小寫英文字母以及括號的字串,該字串括號必定成對出現(well-formed),寫一個method將所有括號內的字串反轉並回傳

ex:
reverseInParentheses(inputString) = "foobazrabblim"
因為 "foo(bar(baz))blim" => "foo(barzab)blim" => "foobazrabblim"

最初看到這個問題時是用迴圈+stack去解析成對的括號,做是做出來了,只是code較為複雜

string reverseInParentheses(string inputString) {
    Stack<char> st = new Stack<char>();
    foreach(var ch in inputString)
    {
        if(ch == ')')
        {
            List<char> tempList = new List<char>();
            while(st.Any())
            {
                char p = st.Pop();
                if(p == '(')
                {
                    break;
                }
                tempList.Add(p);
            }
            tempList.ForEach(x => st.Push(x));
        }
        else  
        {
            st.Push(ch);
        }
    }
    return string.Join("", st.Reverse());
}

最近終於改寫了一個使用正規表示的方法,看起來精簡些了,使用了正規表示+遞迴

先擷取出括號的字串,將其反轉後取代原字串,反覆執行直到整個字串都處理完畢,\w的匹配為[A-Za-z0-9_],每次匹配時只對配到括號內包含[A-Za-z0-9_]的,至於括號包括號的則等到下一輪處理

string reverseInParentheses(string inputString) {

    var pattern = @"\((?<reverseStr>\w*)\)";

    if(!Regex.Match(inputString, pattern).Success)
        return inputString;

    return reverseInParentheses(
        Regex.Replace(inputString, pattern, 
        x => string.Concat(x.Groups["reverseStr"].Value.Reverse())
    ));
}

正規表示中括號代表match括號內的任一字元;小括號代表match括號內的整個pattern,並且將結果存至一個變數中。如果搞錯小括號與中括號的意義就不能如預期擷取了

小括號匹配的pattern還可以取個名字

注意到語法中的 \( 與 \) 是放在小括號的外面的,因此擷取到的部分(reverseStr)已經沒有括號,直接反轉後取代就可以了

LinqPad可以看到Groups的Value部分

參考:

https://codesignal.com/