第26次文章:正則表達式
- 2019 年 10 月 8 日
- 筆記
正則表達式專場,歡迎閱讀喲!
一、正則表達式簡介regular expression
1、為什麼需要正則表達式
文本的複雜處理。
2、正則表達式的優勢和用途
一種強大而靈活的文本處理工具。大部分程式語言、資料庫、文本編輯器、開發環境都支援正則表達式
3、正則表達式定義
正如他的名字一樣是描述了一個規則,通過這個規則可以匹配一類字元串。學習正則表達式很大程度上就是學習正則表達式的語法規則。
4、開發中使用正則表達式的流程
(1)分析所要匹配的數據,寫出測試用的典型數據
(2)在工具軟體中進行匹配測試
(3)在程式中調用通過測試的正則表達式
二、正則表達式語法
1、標準字符集合
(1)能夠與『多種字元』匹配的表達式
(2)注意區分大小寫,大寫是相反的意思

2、自定義字符集合
[]方括弧匹配方式,能夠匹配方括弧中任意一個字元

(1)正則表達式的特殊符號,被包含到中括弧中,則失去特殊意義,除了^,-之外。
(2)標準字符集合,除小數點外,如果被包含於中括弧,自定義字符集合將包含該集合。比如:[d. -+]將匹配數字、小數點、+、-
3、字元邊界
本組標記匹配的不是字元而是位置,符合某種條件的位置-零寬

b 匹配這樣一個位置:前面的字元和後面的字元不全是w
4、匹配模式
(1)IGNORCASE忽略大小寫模式
匹配時,忽略大小寫。默認情況下,正則表達式是要區分大小寫的。
(2)SINGLELINE單行模式
整個文本看做一個字元串,只有一個開頭,一個結尾。使小數點「.」可以匹配包含換行符(n)在內的任意字元。
(3)MULTILINE多行模式
每行都是一個字元串,都有開頭和結尾。在指定了MULTILINE之後,如果需要僅匹配字元串開始和結束為止,可以使用A和Z
5、選擇符和分組

6、反向引用(nnn)
對一個正則表達式模式或部分模式兩邊添加圓括弧,將導致相關匹配存儲到一個臨時緩衝區中,所捕獲的每個子匹配都按照在正則表達式模式中從左到右出現的順序存儲。緩衝區編號從 1 開始,最多可存儲 99 個捕獲的子表達式。每個緩衝區都可以使用 n 訪問,其中 n 為一個標識特定緩衝區的一位或兩位十進位數。通過反向引用,可以對分組已捕獲的字元串進行引用。
7、預搜索(零寬斷言)
(1)只進行子表達式的匹配,匹配內容不計入最終的匹配結果,是零寬度。
(2)這個位置應該符合某個條件。判斷當前位置的前後字元,是否符合指定的條件,但不匹配前後的字元。是對位置的匹配。
(3)正則表達式匹配過程中,如果子表達式匹配到的是字元內容,而非位置,並被保存到最終的匹配結果中,那麼就認為這個子表達式是佔有字元的;如果子表達式匹配的僅僅是位置,或者匹配的內容並不保存到最終的匹配結果中,那麼就認為這個子表達式是零寬的。佔有字元還是零寬度,是針對匹配的內容是否保存到最終的匹配結果中而言的。

三、正則表達式在java中的應用
在java中如果需要使用正則表達式,可以按照既定的步驟進行實現。
1、具體步驟
(1)把正則表達式表示成java中的一個對象
(2)把正則表達式和目標字元串通過matcher對象關聯起來
(3)利用matches方法進行查找
2、簡單實現
(1)首先來簡單測試一下正則表達式的基本用法
public class Demo01 { public static void main(String[] args) { //在這個字元串:shdakhskhfdkjs214654321,是否符合指定的正則表達式:w+ //表達式對象 Pattern p = Pattern.compile("\w+"); //創建Matcher對象 Matcher m = p.matcher("shdakhskhfd&&kjs214654321"); boolean yesorno = m.matches();//嘗試將整個字元序列與該模式匹配 System.out.println(yesorno); System.out.println(m.find());//該方法掃描輸入的序列,查找與該模式匹配的下一個子序列 System.out.println(m.group());//group()返回匹配到的字元串子序列 System.out.println(m.find()); System.out.println(m.group()); }}
結果圖:

tips:
(1)我們按照上述的基本步驟進行建立對象,當我們獲取到matcher對象之後,主要就是根據matcher對象的方法,對目標字元串進行相應的處理。
(2)我們主要使用了matches()、group()和find()函數,三個函數的主要用法都已經在注釋中標出。
需要注意一點的是,在使用正則表達式的轉義字元的時候,我們的正則語法是在字母前面加' ',但是在Java中,所有的' ',都需要變為' '。這一點需要各位小夥伴注意一下哈!
(2)測試分組處理
public class Demo02 { public static void main(String[] args) { //表達式對象 Pattern p = Pattern.compile("([a-z]+)([0-9]+)"); //創建Matcher對象 Matcher m = p.matcher("dsjdag4564**dsg4654**djs654"); while(m.find()) { System.out.println(m.group());//group(),group(0)匹配整個表達式的字元串 System.out.println(m.group(1)); System.out.println(m.group(2)); } }}
結果圖:

tips:
(1)在這段程式碼中,比較好的解釋了正則表達式中分組的概念,我們的正則表達式是匹配字元串和數字的混合模式,在正則表達式中,我們使用小括弧將字元串和數字進行了一個小的分組。所以,當我們使用find函數的時候,首先會在整個目標字元串中尋找符合正則表達式的子字元串,然後在尋找到的子字元串中,會根據我們在正則表達式中的「(」,將每一個括弧中匹配到的內容重新編號,這樣我們可以使用Java中的group(int)進行調用每一個小括弧中的正則表達內容。
(2)比如在我們這段程式碼中,我們的正則表達式由兩個小括弧共同完成,分別代表著字元串和數字。而字元串處於第一個小括弧中,數字處於第二個小括弧中,所以在while循環中,我們可以使用group(int)的方式輸出每一個捕獲組。
四、做一個網路爬蟲
我們利用上面的正則表達式,結合我們前面學習到的網路編程知識,來編寫一個網路爬蟲的小程式,將一個網頁中所包含的網址全部爬取出來。程式碼如下:
package com.peng.regex.test; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net.URL;import java.nio.charset.Charset;import java.util.ArrayList;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern; /** * 網路爬蟲取鏈接 * @author 趙曉鵬 * */public class WebSpiderTest { public static void main(String[] args) { String destStr = getURLContent("http://www.163.com","gbk"); String regStr = "href="([\w\s./:]+?)"";//正則表達式 List<String> list = getMatcherSubstrs(destStr,regStr);//取到的超鏈接的地址 for(String temp:list) { System.out.println(temp); } } /** * 從匹配到的字元串中篩選出子字元串 * @param destStr * @param regStr * @return */ public static List<String> getMatcherSubstrs(String destStr,String regStr){ List<String> list = new ArrayList<String>();//創建一個字元串容器,用於存儲字元串數組 Pattern p = Pattern.compile(regStr);//匹配正則字元串 Matcher matcher = p.matcher(destStr);//將正則表達式與目標字元串進行匹配 while(matcher.find()) { list.add(matcher.group(1));//將正則表達式中的第一個分組存入容器中 } return list; } /** * 獲得urlStr對應的網頁的源碼內容 * @param urlStr 傳入需要爬取的網路地址 * @param charset 指定的編碼集,避免在解碼的時候出現亂碼 * @return */ public static String getURLContent(String urlStr,String charset) { StringBuilder sb = new StringBuilder(); try { URL url = new URL(urlStr);//將網址傳輸進來 BufferedReader reader = new BufferedReader(new InputStreamReader (url.openStream(),Charset.forName(charset)));//為此網路連接打開一個輸入流 String tempStr ; while((tempStr = reader.readLine())!=null) { sb.append(tempStr);//將目標網頁的源碼全部連接在一起,成為一個字元串 } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return sb.toString();//以字元串的形式返回 }}
結果圖:

tips:
在這段網路爬蟲的程式碼中,我們自己編寫了一個獲取網站源碼的方法getURLContent(),以及一個匹配正則表達式的方法getMatcherSubstrs()。我們首先利用getURLContent()方法獲取到了一個網站的源碼。經過對源碼的分析之後發現,源碼中包含的各個網路地址鏈接的格式都是較為固定的,所有的網址的格式均為:href="字元串+空白符+.+/",所以我們在使用正則表達式的時候,將其中的href作為開頭,然後將後面的網址資訊用一個小括弧包圍起來作為一個捕獲組,然後就可以在整個網站的源碼中進行篩選,並取出每個捕獲組,就可以獲得我們的目標資訊。