iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
自我挑戰組

解三十天的 CodeWars系列 第 8

String incrementer

  • 分享至 

  • xImage
  •  

CodeWars 題目

Link

難度

5 kyu

題目

將字串結尾的數字部分遞增,若不是數字則加上一個 1。
並且維持數字的字元數量,例如:012 → 013。

思路

使用正則表達式,將字串拆成兩段;
前面可能有字串或數字,但結尾必須只有數字。
捕獲數字的部分,如果字尾獲取不到,就直接+1。

利用字串長度,確保遞增後的數字長度與原本相同。

pseudo code

let reg = /^(...)(...)$/
let result = str.match(reg)
if(!result) return str + "1"

return result[1] + (result[2]+1)

實作

function incrementString(strng) {
   let regExp = /^(.*?)(\d+)$/;
   let result = strng.match(regExp);
   if (!result) return strng + "1";
   let number = +result[2] + 1;
   return result[1] + "0".repeat(Math.max(result[2].length - String(number).length, 0)) + number;
}

使用 () 可個別捕獲不同的正則條件,match 利用匹配的結果建立陣列。

/^(.*?)(\d+)$/

  • ^ 表示匹配開頭,$ 表示匹配結尾;有從頭驗證到尾的意思。
  • 第一個捕獲組 (.*?)表示匹配任意數量的字元,但以後面的捕獲分組為主。
    • . 表示單一字元;* 表示零到多次;? 表示零或一,在這裡為表示匹配較少。
    • foobar00999 為例,若第一捕獲有 ? 限制:["foobar00999", "foobar", "00999"]
    • 若第一捕獲無 ? 限制:["foobar00999", "foobar0099", "9"]
  • 第二個捕獲組(\d+)表示匹配一到多次的數字。

match 返回的結果,將數字的部分 +1。

原始匹配的長度、扣掉轉換成數字並遞增後的長度,Math.max 與 0 取最大值(因為可能有負數),得到 repeat 計算需要補的 0 的次數;最後跟第一捕獲組拼接出結果。

他人的解法

let incrementString = str => str.replace(/([0-8]|\d?9+)?$/, (e) => e ? + e + 1 : 1)

直接使用 replace 方法,會返回處理後的字串。

正則表達式可多次拆分來看:

(…)?$ 表示符合 () 捕獲條件零或一次,$ 表示這個捕獲在字串結尾。

裡面的條件 [0-8]|\d?9+ 可能有兩種情況;結尾數字由 0-8 組成,或者最後位為 9,一次或多次的 9,且前面拼接一個或零個數字 0-9。

這個做法用意是分為要進位,以及不用進位兩種狀況;如果不需進位就獲取最後尾一個數字。

如果需要進位,則獲取字尾數來的連續的 9,以及它前面的數字。

符合條件一:foobar000,只捕獲最後一個 0
符合條件二:foobar00999,捕獲 0999

第二參數的三元運算子,如果符合條件則將 match 的內容轉為數字後+1,若不符合條件則表示沒有數字做為結尾,則返回 1。

心得

如果要問我自學過程中,理解哪些知識點時最讓我煎熬?
我第一個想到遞迴、第二大概就是正則表達式。

(不過自從學了 Functional Programming,又再加上 Functional Programming🫠)

不過,越是解題就越是感受到正則的強大,
搭配一些簡單的方法就能辦到很多事、解決很多問題。
有機會一定要找一下訓練寫正則條件的平台‼️


上一篇
First non-repeating character
下一篇
Moving Zeros To The End
系列文
解三十天的 CodeWars30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言