正則表示式(模式器,匹配器)及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天