Java - Regular Expression for 檢查時間格式

在這邊舉的例子是如何透過正規表示式來檢查時間格式(hh:mm:ss.SSS),輸入的部分需要符合正規表示式,但是若輸入了不完整的資訊,在此的作法是程式會幫您自動轉換,而非一個正規表示式可以通吃所有資料格式!

規則說明如下:
#格式:
hh:mm:ss.SSS => 時:分:秒.毫秒

#輸入:
1. 單一數字如100,表示秒,檢查格式前程式自動轉換成00:01:40
2. 單一數字加小數點如100.333,整數表示、小數點表示毫秒,檢查格式前程式自動轉換成00:01:40.333
3. 不完整資訊如01:40,在此表示mm:ss,檢查格式前程式自動轉換成00:01:40
4. 完整資訊如00:01:40,不需做轉換動作!

#輸出:
Match or Not Match

程式說明如下:
首先,請輸入一時間,這個時間會先透過autoAssignFormat進行格式轉換,統一轉成hh:mm:ss的形式,而提供自動轉換的目的在於方便輸入者不需輸入完整的格式。這時也許會疑惑為啥不直接交由正規表示式判斷就好了? 只能說這裡撰寫的正規表示式只單純判斷hh:mm:ss.SSS,頂多輸入的資訊可以接受少輸入毫秒(SSS)!
public static void main(String[] args) {
    // TODO Auto-generated method stub
    final String PATTERN = "([\\d]+):([0-5]\\d):([0-5]\\d\\.?\\d{0,3})";
    Scanner input = new Scanner(System.in);
    try {
       while(true) {
          System.out.println("Please input time: (hh:mm:ss.SSS or ss)");
          String time = input.nextLine();
    
          System.out.println("You input: "+time);
          time = autoAssignFormat(time);
    
          System.out.println("After convertion: "+time);
          if(time.matches(PATTERN)) {
             System.out.println("Match!!");
          }else {
             System.out.println("Not Match!!");
          }
          System.out.println("=======================================");
      } 
    }catch (NumberFormatException e) {
       System.out.println("Convertion error! "+e.getMessage());
    }finally {
       input.close();
    } 
}

而自動轉換的方式也很簡易,首先若有兩個冒號則視為輸入hh:mm:ss,但若小於兩個冒號則判斷為mm:ss或ss,此時就會先轉成秒數再重新組成! 因此您可以輸入大於59的秒或分!
private static String autoAssignFormat(String value) throws NumberFormatException{
   value = value.trim();
   String ch[] = value.split(":", -1);
   if(ch.length > 1){
      if(ch.length < 3){
         return convertToTimeFormat(convertToSec(ch));
      }else{
         return value;
      }
   }else{
      return convertToTimeFormat(Double.parseDouble(value));
   }
}

private static double convertToSec(String unit[]) throws NumberFormatException{
   double sec = 0;
   int [][]convert = {{1}, {60, 1}};
   for(int i = 0 ; i < unit.length ; i++){
      sec = sec + (Double.parseDouble(unit[i]) * convert[unit.length - 1][i]);
   }
   return sec;
}

再來是呼叫重組成時間格式的code
private final static DecimalFormat df = new DecimalFormat("#.###");
private static String convertToTimeFormat(double sec) throws NumberFormatException{
   //input value unit is seconds
   StringBuilder format = new StringBuilder();
   String time[] = new String[3];
   time[0] = String.valueOf((int)(sec / 3600));
   time[1] = String.valueOf((int)((sec % 3600) / 60));
   double ss = sec % 60;
   time[2] = df.format(ss);
   for(int i = 0 ; i < time.length ; i++){
      if(i == 2){
         format.append(ss >= 10 ? time[i] : "0"+time[i]);
      }else{
         format.append(time[i].length() == 1 ? "0"+time[i] : time[i]).append(":");
      }
   }
   return format.toString();
}

再來就是matches pattern ([\\d]+):([0-5]\\d):([0-5]\\d\\.?\\d{0,3})的說明
hh的部分不限制0~23
()表示一個group,group之間指定需要有:的符號存在,因此若少於兩個冒號則會不match。
[]內指定須符合那些範圍的字元,若不指定哪一範圍的數字則以\\d表示,+表示不限長度的數字,[0-5]\\d表示 0 ~ 59。
?表示可有可無的狀況,如在這裡是搭配逗點,因此輸入的秒數為整數pass,而浮點數的話由於\\d{0,3}表示0~3組的數字,因此也能夠pass。

DEMO如下:

留言