1. 程式人生 > >正則表示式(模式器,匹配器)及java中的日期表示

正則表示式(模式器,匹配器)及java中的日期表示

正則表示式

正則表示式:用於匹配某些特定字串的一個規則。

沒有學會使用正則表示式的時候,我們遇到過這麼一個需求-----校驗使用者名稱是否合法?

具體要求如下:

1)使用者名稱長度必須在6到15之間

2)必須是字母數字組合

非正則具體實現如下

public class Regex {
    public static void main(String[] args) {
        //1)使用者名稱長度必須在6到15之間
        //2)必須是字母數字組合
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入使用者名稱:");
        String s = sc.nextLine();
        if(s.length()>=6 && s.length()<=15){
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if((c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c>='0'&&c<='9')){
                    System.out.println("使用者名稱正確");
                    break;
                }else{
                    System.out.println("必須是字母數字組合");
                    break;
                }
            }
        }else{
            System.out.println("使用者名稱長度必須在6到15之間");
        }
    }
}

看起來十分的繁瑣,目前的要求只有兩個,如果我們要在加一個並且使用者名稱不能以0開頭。就必須在原來基礎上繼續巢狀判斷條件,這樣顯得程式十分雍容,當然不採用這種方式了。事實上這些需求在正則面前就顯得弱爆了。請看正則表演:

正則具體實現如下

public class Regex {
    public static void main(String[] args) {
        //1)使用者名稱長度必須在6到15之間
        //2)必須是字母數字組合
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入使用者名稱:");
        String s = sc.nextLine();
        String regex = "[0-9A-Za-z]{6,15}";
        if (s.matches(regex)) {
            System.out.println("使用者名稱合法");
        }else{
            System.out.println("使用者名稱長度必須在6到15之間,必須是字母數字組合");
        }
    }
}

沒錯,實際校驗的程式碼就兩行,這就是正則表示式的強大之處。

我們來分析一下這裡的正則表示式,[0-9A-Za-z]這裡是一個組合的寫法表示可以是0-9或者任意大小寫字母的組合也可以寫成預定義字元\\w也是表示0-9或者任意大小寫字母的組合。

{6,15}這個是表示數量,具體就是這裡的使用者名稱的長度必須在6到15之間。

再來看一個需求

校驗郵箱,要求郵箱的字首名必須是4-12位的數字字母組合且不能以0開頭

public class CheckEmail {
    public static void main(String[] args) {
        //字首名必須是4-15位的數字字母組合且不能以0開頭
        //定義正則表示式
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入你的郵箱:");
        String regex ="[1-9a-zA-Z][0-9a-zA-Z]{3,15}@[a-z1-9]{1,10}\\.(com|cn|net|org|edu)";
        String s = sc.nextLine();
        if(s.matches(regex)){
            System.out.println("郵箱格式正確");
        }else{
            System.out.println("郵箱格式不正確");
        }

    }
}

模式器(Pattern)和匹配器(Matcher)

模式器:用於封裝正則表示式(某種特定規則的類)

匹配器:用於匹配模式器的類,該類提供了許多方法

API提供的呼叫順序

Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();

我們現在就來用模式器和匹配器改寫剛才的校驗郵箱的程式

public class CheckEmail {
    public static void main(String[] args) {
        //字首名必須是4-15位的數字字母組合且不能以0開頭
        //定義正則表示式
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入你的郵箱:");
        String regex ="[1-9a-zA-Z][0-9a-zA-Z]{3,15}@[a-z1-9]{1,10}\\.(com|cn|net|org|edu)";
        String s = sc.nextLine();
        Pattern p = Pattern.compile(regex); //獲得模式器物件
        Matcher m = p.matcher(s);//獲取匹配器物件
        boolean flag = m.matches();//校驗
        if(flag){
            System.out.println("郵箱格式正確");
        }else{
            System.out.println("郵箱格式不正確");
        }

    }
}

疑問:之前我用過String類的matcher方法直接一下就可以實現了這個功能,為什麼還要再定義一個模式器匹配器,豈不多此一舉?

回答:在這個功能中是多餘的,我只是舉個例子,但是java給我提供這兩個類肯定還有別的用處,這裡只是簡單的判斷是否符合該正則表示式,但是如果一個需求中需要我們獲取滿足該正則表示式的欄位,我們該如何獲取呢,這下就需要使用Pattern和Matcher了,請看這個需求:

從這個字串中找出所以由四個單片語成的字元序列

"wo ai bei jing tian an men, tian an men shang tai yang sheng"

 在寫程式碼前,介紹一下Matcher類給我們提供的兩個方法

public boolean find() 嘗試查詢與該模式匹配的輸入序列的下一個子序列。結果返回true,反正false
public String group() 返回由以前匹配操作所匹配的輸入子序列。
public class PMDemo {
    public static void main(String[] args) {
        String s = "wo ai bei jing tian an men, tian an men shang tai yang sheng";
        String regex = "[a-zA-Z]{4}";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(s);
        while (m.find()) {
            System.out.println(m.group());
        }
    }
}

執行結果如下

jing
tian
tian
shan
yang
shen 

提問:需求實現了嗎?

回答:實現了啊 !

再問:你確定,你在仔細看看,shan,shen 是什麼東東?

回答:emm。。。。。

解答:這裡存在一個單詞邊界的問題,需要區分單詞開頭和結尾,改進程式碼如下

public class PMDemo {
    public static void main(String[] args) {
        String s = "wo ai bei jing tian an men, tian an men shang tai yang sheng";
        String regex = "\\b[a-zA-Z]{4}\\b";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(s);
        while (m.find()) {
            System.out.println(m.group());
        }
    }
}

 執行結果

jing
tian
tian
yang

 日期類

需求1:按格式輸出現在的時間,例如(2018年10月29日 16:24:32 星期一)

public class DateDemo2 {
    public static void main(String[] args) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss E");
        String format = simpleDateFormat.format(new Date());
        System.out.println(format);
    }
}

執行結果:

2018年10月29日 17:09:04 星期一

需求2:任意輸入一個年份,輸出該年的二月有多少天?

提問:那你寫個演算法吧

回答:好吧!

public class FIndE {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入一個年份");
        int year =sc.nextInt();
        if((year%4==0&&year%100!=0)||year%400==0){
            System.out.println(year+"二月份有29天");
        }else
            System.out.println(year+"二月份有28天");
    }
}

請輸入一個年份
2008
2008二月份有29天 

提問:實現了吧

回答:對呀,請看程式碼

再提問:請寫出方法二

回答:emm。。。。(沉默)

解答:我們可以利用Calendar類中的方法獲得該年份的三月的第一天,然後天數減一不就得到二月份的最後一天是幾號了嗎!這才叫面向物件思想,學著點。

public class FIndE {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入一個年份");
        int year =sc.nextInt();
        Calendar ins = Calendar.getInstance();//獲取日期類物件
        ins.set(year,2,1);//注意:外國人寫的方法每年十二個月表示是從0月到11月的,所以這裡應該寫2月
        ins.add(Calendar.DAY_OF_MONTH,-1);//三月一號減一
        System.out.println(year+"年二月份一共有"+ins.get(Calendar.DAY_OF_MONTH)+"天");//獲得這一天在該月份中的第幾天

    }
}

執行結果:

請輸入一個年份
2018
2018年二月份一共有28天

需求3:輸入一個日期,算一下那一天離今天多少天了

提問:如何將字串型別轉換為時間型別

解答:通過SimpleDateFormat類中的parse方法

public class SimpleDateFormatDemo {
    public static void main(String[] args) throws ParseException {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入一個日期 格式為2018年10月27日");
        String day = sc.nextLine();
        SimpleDateFormat smp = new SimpleDateFormat("yyyy年MM月dd日");
        Date date = smp.parse(day);
        long time = date.getTime();
        long now = System.currentTimeMillis();
        System.out.println(day+"與今天相距"+(now -time)/1000/60/60/24+"天");
    }
}

執行結果:1997年7月30日與今天相距7761天