題目描述

完成一個名稱為「myRegex」的類別,這個類別包含了一個字串樣本。您必須寫出一個正規表示式提供給這個樣本使用,使它可以被用來驗證IP位址。



IP位址的定義如下:

IP位址是一個字串,格式為「A.B.C.D」,這邊的A、B、C和D代表一個範圍0到255(包含0和255)的整數。整數的前段可以是0,如001、025。A、B、C和D的字串長度,不可以超過3。

一些合法的IP位址如下:

000.12.12.034
121.234.12.12
23.45.12.56

一些不合法的IP位址如下:

000.12.234.23.23
666.666.23.23
.213.123.23.32
23.45.22.32.
I.Am.not.an.ip

在這個題目中,您將會得到多個由ASCII字元組成的字串,您必須寫出正規表示式,來找出這些字串中哪些是合法的IP位址。注意myRegex類別不可以使用public修飾。

原題網址

範例輸入

000.12.12.034
121.234.12.12
23.45.12.56
00.12.123.123123.123
122.23
Hello.IP

範例輸出

true
true
true
false
false
false

解題概念

不超過3位數,範圍0到255且可以由0開頭的整數字串的正規表示式該如何撰寫呢?

首先考慮到「25X」的情況,X的範圍只能在0到5(包含0和5),因此可以寫出以下正規表示式(數值範圍為250到255):

"25[0-5]"

再來考慮到「2XY」但不是「25X」的情況,X的範圍只能在0到4(包含0和4),Y的範圍可以是0到9(包含0和9),因此可以寫出以下正規表示式(數值範圍為200到249):

"2[0-4][0-9]"

再來考慮到「1XY」的情況,X和Y的範圍都可以是0到9(包含0和9),因此可以寫出以下正規表示式(數值範圍為100到199):

"1[0-9][0-9]"

再來考慮到「0XY」的情況,X和Y的範圍都可以是0到9(包含0和9),開頭的0和X可以被省略掉,因此可以寫出以下正規表示式(數值範圍為000到099、00到99、0到9):

"[0]?[0-9]?[0-9]"

用OR運算合併以上式子,不超過3位數,範圍0到255且可以由0開頭的整數字串的正規表示式可以撰寫如下:

"25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9]"

IP位址的格式中,0到255的整數有4個,每個整數中間都使用「.」來分隔,可以很直覺的寫出以下正規表示式:

"(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])"

化簡重複的部份後,得到:

"((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])"

若I為「(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])」,繼續化簡,得到:

"(I.){3}I"

由於IP不能是「A0.0.0.0B」等等的字串,因此還需要加上字串的起頭與結尾判斷,所以最後的正規表示式為:

"\\A(I.){3}I\\z"

要將I替換回「(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])」。

參考答案

import java.util.Scanner;

public class Solution {

    public static void main(final String[] args) {
        final Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            final String IP = in.next();
            System.out.println(IP.matches(new myRegex().pattern));
        }
    }
}

class myRegex{
    private static final String REGEX_0_TO_255 = "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0]?[0-9]?[0-9])";
    public final String pattern = String.format("\\A(%s\\.){3}%s\\z", REGEX_0_TO_255, REGEX_0_TO_255);
}