js正則格式化日期時間自動補0

獨書先生 發表於 2021-10-13

原文 js正則格式化日期時間自動補0

背景

時間日期格式化的需求很常見,也有很多工具類轉換方法,比如需要將2022-3-4這種日期格式轉化為2022-03-04,也就是實現個位數月份或天數日期自動前置補 0。用moment.jsdayjs第三方庫的 API 也很容易做到,這裡我們自己實現一下看看。

解法一

思路:

先來看看常規方案。就用這個2022-3-4日期來舉例子,我們先根據-切分字串,得到一個陣列,然後分別識別34這種個位數日期,<10就前置補 0,否則不操作。

程式碼:

function formatDate(str) {
  // 根據 - 符號拆分
  return str
    .split("-")
    .map((item) => {
      // +item 將item字串轉換為數字
      // 小於10的時候就補全一個字首0
      if (+item < 10) {
        return "0" + +item;
      }

      // 大於10的時候不用補0
      return item;
    })
    .join("-"); // 最後重組回來
}

// 測試
formatDate("2022-03-4"); // 輸出 '2022-03-04'

上面這個方案,只適配了2022-3-42022-03-04這種簡單的轉換,更復雜的日期格式或者日期時間格式,比如2022-3-4 1:2:3還不能匹配到。
而且,我們這裡只識別了-這一種格式,假如還有2022/3/42022.3.4這種寫法呢?

解法二

思路:

再來看看用正規表示式,用正規表示式不僅可以簡化程式碼,還能更容易的相容更多情況。

我們的核心思路是用前瞻後顧來識別日期連線符號中間的數字,然後判斷數字是否需要補全 0。寫之前,先來熟悉幾個正規表示式的用法。

  1. 前瞻:(?=),後顧:(?<=)

    簡單來理解,就是

    // 前瞻:
    A(?=B)   //查詢B前面的A
    
    // 後顧:
    (?<=B)A   //查詢B後面的A
    
    // 負前瞻:
    A(?!B)   //查詢後面不是B的A
    
    // 負後顧:
    (?<!B)A   //查詢前面不是B的A
    

    我們這裡可以用來識別-/.等字元之間的數字

  2. 單詞邊界:\b

    • 單詞指的是\w可以匹配的字元,即數字、大小寫字母以及下劃線 [0-9a-zA-Z_]
    • 邊界 指的是佔位的字元左右的間隙位置

    我們這裡可以用於識別-到日期開始或結束位置的數字,比如2022-3-4 1:2:5中,4後面的間隙,1前面的間隙,5後面的間隙,都是單詞邊界

  3. replace方法替換匹配的字串:$&

    匹配到個位數數字之後,還要補 0,$&就是代表匹配到的數字,用0$&就可以實現補 0。

程式碼:

// 使用$&匹配
function formatDate(str) {
  /*  
        replace第一個引數正則

        (?<=\/|-|\.|:|\b)\d{1}  用的是後顧,查詢 / 或者 - 或者 . 或者 : 或者 單詞邊界 或者 T 後面的一個數字

        \d{1}(?=\/|-|\.|:|\b)   用的是前瞻,查詢 / 或者 - 或者 . 或者 : 或者 單詞邊界  或者 T 前面的一個數字

        replace 第二個引數"0$&" 匹配到的字串前置補0

    */
  return str.replace(/(?<=\/|-|\.|:|\b|T)\d{1}(?=\/|-|\.|:|\b|T)/g, "0$&");
}

// 使用$1匹配
function formatDate(str) {
  /*
        replace第一個引數正則和上面的一樣
        
        replace 第二個引數是一個函式,第一個入參就是匹配到的第一個引數,可以在函式內處理補0
    */
  return str.replace(
    /(?<=\/|-|\.|:|\b|T)\d{1}(?=\/|-|\.|:|\b|T)/g,
    function ($1) {
      return "0" + $1;
    }
  );
}

// 測試
formatDate("2022-3-4 1:2:3"); // 輸出 '2022-03-04 01:02:03'
formatDate("2022/3/4"); // 輸出 '2022/03/04'
formatDate("2022.3.4"); // 輸出 '2022.03.04'
formatDate("2020/8/9T1:2:3"); // 輸出 '2020/08/09T01:02:03'

總結

我們這裡只是做了普通字串的轉換,也有些缺點

  1. 日期校驗沒有內建
  2. 類似01/10/07這種簡寫的日期格式也沒有考慮在內

感興趣的朋友可以發揮下,豐富下我們的轉換方法。

參考

原文來自 https://lwebapp.com

更多程式設計師工具箱:https://lwebapp.com/zh/tools