1. 程式人生 > >37-正則表示式(概述+符號+對字串的常見操作(正則的四個功能))+Pattern+Matcher+練習題

37-正則表示式(概述+符號+對字串的常見操作(正則的四個功能))+Pattern+Matcher+練習題

一、正則表示式概述

1、正則表示式:用於操作字串資料,通過一些特定的符號體現

2、String類中

(1)public boolean matches(String regex):告知此字串是否匹配給定的正則表示式。呼叫此方法的str.matches(regex)形式與以下表達式產生的結果完全相同:Pattern.matches(regex, str)

注:引數regex:具備一定規則的字串,即用來匹配字串的正則表示式

3、正則表示式雖然簡化了書寫,但閱讀性變差了

二、正則表示式的符號

1、字元類

(1)[abc]:字串的某一位上的字元,必須是:a或b或c

(2)[^abc]:除了a、b、c之外的任何字元

(3)[a-zA-Z]:a到z或A到Z,即 所有大小寫字母

(4)[a-d[m-p]]:並集,a到d或m到p,即 [a-dm-p]

(5)[a-z&&[def]]:交集,a到z && d或e或f,即 [def]

(6)[a-z&&[^bc]]:交集,a到z && 非b到c, 即 [ad-z]

(7)[a-z&&[^m-p]]:交集,a到z && 非m到p,即 [a-lq-z]

2、預定義字元

(1).任何字元

(2)\d:數字[0-9]

(3)\D:非數字[^0-9]

(4)\w:單詞字元[a-zA-Z_0-9],即 數字、字母(含大小寫)、下劃線

(5)\W:非單詞字元[^\w]

(6)\s:空白字元[ \t\n\x0B\f\r]

(7)\S:非空白字元[^\s]

3、邊界匹配器

(1)^:行的開頭

(2)$:行的結尾

(3)\b:單詞邊界(單詞與單詞之間的空格)

(4)\B:非單詞邊界

(5)\A:輸入的開頭

(6)\G:上一個匹配的結尾

(7)\Z:輸入的結尾,僅用於最後的結束符(如果有的話)

(8)\z:輸入的結尾

4、Greedy數量詞

(1)X?:X,一次或一次也沒有

(2)X*:X,零次或多次(有也行,沒有也行)

(3)X+:X,一次或多次

(4)X{n}:X,恰好n次

(5)X{n, }:X,至少n次

(6)X{n, m}:X,至少n次,但是不超過m次

        String str = "abcabcd";
        String regex = "[abc]+d";
        System.out.println(str.matches(regex)); //true

三、正則表示式對字串的常見操作(正則的四個功能)

!!!匹配、切割、替換這些功能,底層用的都是Pattern物件的方法。因為正則模式作用於字串只有一個物件:Pattern

eg:字串中的matches(regex)方法,底層用的就是正則表示式中正則物件的matches()方法Pattern.matches(regex, str)

1、匹配:使用的是String類中的matches(regex)方法

                public boolean matches(String regex)

        //匹配手機號碼是否正確
        String phoneNum = "13522943355";
//        String regex = "1[358][0-9]{9}";
        // \d:表示[0-9]的數字
        //反斜槓(\)在字串中會自動對其後的字元進行轉義,所以要使用\\d
        String regex = "1[358]\\d{9}";
        boolean result = phoneNum.matches(regex);
        System.out.println(phoneNum + ":" + result);

2、切割:使用的是String類中的split(regex)方法

                public String[] split(String regex)

        //用空格切割姓名
        String str = "zhangsan xiaoqiang zhaoliu";
        String[] names = str.split(" ");
        for (String name : names) {
            System.out.println(name);
        }

問:如果姓名之間有多個空格,怎麼切割?

        //用一個或多個空格切割姓名
        String str = "zhangsan     xiaoqiang      zhaoliu";
        // " +":匹配一個或多個空格
        String[] names = str.split(" +");
        for (String name : names) {
            System.out.println(name);
        }
        //用 . 切割姓名
        String str = "zhangsan.xiaoqiang.zhaoliu";
        // ".":在正則表示式中是一個特殊符號,用 \\. 來轉義
        String[] names = str.split("\\.");
        for (String name : names) {
            System.out.println(name);
        }
        //用疊詞切割姓名
        String str = "zhangsantttttxiaoqiangmmmzhaoliu";
        //()代表一個組,\\1代表與第一組相同
        //(.)\\1+:有一個或多個與第一組相同的內容,而第一組是任意字元
        String[] names = str.split("(.)\\1+");
        for (String name : names) {
            System.out.println(name);
        }

分析:疊詞,第二位的內容與第一位一致,意味著第一位的內容被後面複用。如何實現複用?

補充:

(1)正則中,複用的封裝方式:小括號(Java中基本的複用形態是:封裝成函式)。封裝體沒有名字,但會自動編號,從1開始。這種封裝形式稱為組

即 正則規則中用於封裝的形式是小括號。為了能使用這種封裝形式,沒有名字,但有編號。寫一個就是1編號,再寫一個就是2編號

(2)(.):括號()就是組,該組的內容是 . ,即為任意字元。

         \\1:使用第一組的內容。直接用編號n就代表使用第n組的內容,但編號n需要被轉義成\\n

         (.)\\1+:一個任意字元,後面有一個或多個與之相同的字元

(3)正則中的組按左括號來編號,有幾個左括號就有幾個組

eg:((A)(B(C))):有四個組,分別是:

        1:((A)(B(C)))

        2:\A

        3:(B(C))

        4:(C)

(4)正則中,封裝成組來應用,提高規則的複用性

3、替換:使用的是String類中的replaceAll(regex, replacement)方法

                public String replaceAll(String regex, String replacement)

        //將疊詞替換成#
        String str = "zhangsanttttxiaoqiangmmmmmmmzhaoliu";
        //使用replaceAll()方法,第一個引數是需要被替換的內容(正則表示式),第二個引數是替換後的內容
        str = str.replaceAll("(.)\\1+", "#");
        System.out.println("str = " + str);   //str = zhangsan#xiaoqiang#zhaoliu
        //將疊詞替換成一個字元(eg:將多個t變成一個t,將多個m變成一個m)
        String str = "zhangsanttttxiaoqiangmmmmmmmzhaoliu";
        //$n:獲取前一個引數中的第n組的內容
        //$:在其他引數中可以對前一個引數中的已有的正則中的規則進行獲取
        str = str.replaceAll("(.)\\1+", "$1");
        System.out.println("str = " + str);   //str = zhangsantxiaoqiangmzhaoliu

補充:

(1)一個方法的第一個引數帶著正則,第二個引數想使用第一個引數正則中的內容,用$n來表示

(2)$n:獲取前一個引數中的第n組的內容

(3)$:在其他引數中可以對前一個引數中的已有的正則中的規則進行獲取

        //15800001111 --> 158****1111
        String str = "15800001111";
        //將號碼分成三部分。$n是獲取前一個引數中第n組的內容,所以 \\d{3} 要放在一個組中,用(\\d{3})
        str = str.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
        System.out.println("str = " + str);

4、獲取:使用匹配器Matcher中的group()方法

                 String group()

        //獲取str中由3個字母組成的單詞
        String str = "da jia hao , ming tian bu fang jia !";
        //三個字母組成的單詞,單詞的兩邊要有單詞邊界\\b
        String regex = "\\b[a-zA-Z]{3}\\b";
        //將正則封裝成物件
        Pattern p = Pattern.compile(regex);
        //通過正則物件獲取匹配器物件
        Matcher m = p.matcher(str);
        //用Matcher物件的方法對字串進行操作
        //要獲取三個字母組成的單詞,先用find()查詢,再用group()獲取
        while (m.find()) {
            System.out.println(m.group());
            //可以獲取位置(包含頭 不包含尾),相當於indexOf()
            System.out.println(m.start() + "--" + m.end());
        }

四、java.util.regex.Pattern

1、public final class Pattern:正則表示式的編譯表示形式(需要將正則封裝成物件)

2、指定為字串的正則表示式必須首先被編譯為此類的例項(將正則表示式封裝成物件)。然後,可將得到的模式(正則規則)用於建立Matcher物件(匹配器),依照正則表示式,該物件可以與任意字元序列匹配。執行匹配所涉及的所有狀態都駐留在匹配器中,所以多個匹配器可以共享同一模式

注:

(1)將正則封裝成物件(封裝物件,正則沒有對字串進行操作)

(2)建立一個匹配器物件

(3)正則只負責表示式的封裝,要想用表示式操作字串,必須要獲取匹配器物件。匹配器物件用規則操作字串,按規則對字串進行匹配。匹配的結果都在匹配器中

        //將正則規則進行物件的封裝
        Pattern p = Pattern.compile("a*b");
        //通過正則物件的matcher()方法和字串關聯,獲取要對字串操作的匹配器物件Matcher
        Matcher m = p.matcher("aaaaab");
        //通過Matcher匹配器物件的方法對字串進行操作
        boolean b = m.matches();

3、方法

(1)static Pattern compile(String regex):將給定的正則表示式編譯到模式中

(2)static Pattern compile(String regex, int flags):將給定的正則表示式編譯到具有給定標誌的模式中

(3)int flags():返回此模式的匹配標誌

(4)Matcher matcher(CharSequence input):建立匹配給定輸入與此模式的匹配器

(5)static boolean matches(String regex, CharSequence input):編譯給定正則表示式並嘗試將給定輸入與其匹配

        //以下兩行程式碼的行為完全相同
        Pattern.matches(regex, input);  //便捷方式
        Pattern.compile(regex).matcher(input).matches();

注:如果要多次使用一種模式,編譯一次後重用此模式比每次都呼叫此方法效率更高

(6)String pattern():返回在其中編譯過此模式的正則表示式

(7)static String quote(String s):返回指定String的字面值模式String。此方法產生一個String,可以將其用於建立與字串s匹配的Pattern,就好像它是字面值模式一樣。輸入序列中的元字元和轉義序列不具有任何特殊意義

(8)String[] split(CharSequence input):圍繞此模式的匹配拆分給定輸入序列

(9)String[] split(CharSequence input, int limit):圍繞此模式的匹配拆分給定輸入序列

(10)String toString():返回此模式的字串表示形式。此為在其中編譯過此模式的正則表示式

五、java.util.regex.Matcher

1、public final class Matcher:通過解釋Pattern(正則表示式)對character sequence(字元序列)執行匹配操作的引擎(Matcher是真正用正則表示式操作字串的物件)

2、通過呼叫模式的matcher()方法從模式建立匹配器。建立匹配器後,可以使用它執行三種不同的匹配操作:

(1)matches()方法嘗試將整個輸入序列與該模式匹配

(2)lookingAt()嘗試將輸入序列從頭開始與該模式匹配

(3)find()方法掃描輸入序列以查詢與該模式匹配的下一個子序列

3、部分方法

(1)boolean matches():嘗試將整個區域與模式匹配。如果匹配成功,則可以通過start()、end()和group()方法獲取更多資訊

(2)int start():返回以前匹配的初始索引(返回第一個匹配字元的索引)

(3)int start(int group)

(4)int end():返回最後匹配字元之後的偏移量

(5)int end(int group)

(6)boolean find():嘗試查詢與該模式匹配的輸入序列的下一個子序列(當且僅當輸入序列的子序列匹配此匹配器的模式時才返回true)。此方法從匹配器區域的開頭開始,如果該方法的前一次呼叫成功了並且從那時開始匹配器沒有被重置,則從以前匹配操作沒有匹配的第一個字元開始

(7)boolean find(int start)

(8)String group():返回由以前匹配操作所匹配的輸入子序列。對於具有輸入序列s的匹配器m,表示式m.group()和s.substring(m.start(), m.end())是等效的

(9)String group(int group)

(10)boolean lookingAt():嘗試將從區域開頭開始的輸入序列與該模式匹配。與matches()方法類似,此方法始終從區域的開頭開始;與之不同的是,它不需要匹配整個區域

4、find():查詢,group():獲取。group()獲取之前要先find()查詢,否則報錯 IllegalStateException: No match found。所以,要先拿規則regex到字串str中匹配。find()方法的返回值是boolean型別,想要獲取全部,先要用while(find())迴圈,在迴圈體裡面group()獲取

        //獲取str中由3個字母組成的單詞
        String str = "da jia hao , ming tian bu fang jia !";
        //三個字母組成的單詞,單詞的兩邊要有單詞邊界\\b
        String regex = "\\b[a-zA-Z]{3}\\b";
        //將正則封裝成物件
        Pattern p = Pattern.compile(regex);
        //通過正則物件獲取匹配器物件
        Matcher m = p.matcher(str);
        //用Matcher物件的方法對字串進行操作
        //要獲取三個字母組成的單詞,先用find()查詢,再用group()獲取
        while (m.find()) {
            System.out.println(m.group());
            //可以獲取字串的位置(包含頭 不包含尾),相當於indexOf()
            System.out.println(m.start() + "--" + m.end());
        }

5、匹配器Matcher也可以完成匹配、替換等操作,但字串String中的匹配、替換等方法更為簡單。但獲取功能只能用匹配器Matcher中的方法完成

六、練習題

1、治療口吃:我我我...要...要要...學學學學..編編...編..程....程程  -->  我要學程式設計

        //治療口吃:我我我...要...要要...學學學學..編編...編..程....程程 --> 我要學程式設計
        //用替換
        String str = "我我我...要...要要...學學學學..編編...編..程....程程";
        //先將 . 都去掉。用\\.對.進行轉義
        str = str.replaceAll("\\.+", "");
        System.out.println("str = " + str);
        /**
         * 去掉疊詞
         * (.):一組,該組中的內容為任意字元
         * \\1:使用第一組的內容
         * \\1+:使用第一組的內容一次或多次
         * (.)\\1+:一個任意字元,後面有一個或多個與之相同的字元
         * $1:使用第一個引數中第一組的內容
         */
        str = str.replaceAll("(.)\\1+", "$1");
        System.out.println("str = " + str);

2、對IP地址排序(按IP地址分類排序,每段數字越小越靠前):192.168.10.34    127.0.0.1    3.3.3.3    105.70.11.55

        //對IP地址排序(按IP地址分類排序,每段數字越小越靠前):192.168.10.34    127.0.0.1    3.3.3.3    105.70.11.55
        String str = "192.168.10.34    127.0.0.1    3.3.3.3    105.70.11.55";
        /*
        //將IP地址切出,用一個或多個空格切
        String[] ips = str.split(" +");
        */
        /**
         * 使用TreeSet物件排序 -- 自動排序
         * 問題:TreeSet預設按照字串排序,而需求是按照數值大小排序
         * 錯誤原因:每一段的位數不一樣。如果每一段的位數相同,結果就是正確的
         * 做法:前面補0,每段都加2個零(保證至少是3位),再擷取(保留)後三位
         *
         * 即 為了讓IP可以按照字串順序比較,只要讓IP的每一段位數相同即可。所以,補0
         * 按照每一位所需最多0進行補充,每一段都加2個0
         */
        //每段都補2個0
        str = str.replaceAll("(\\d+)", "00$1");
        //每段保留後三位
        str = str.replaceAll("0*(\\d{3})", "$1");
        //將IP地址切出,用一個或多個空格切
        String[] ips = str.split(" +");

        //將切出的字串放入TreeSet中自動排序
        TreeSet<String> ts = new TreeSet<String>();
        for (String ip : ips) {
            ts.add(ip);
        }

        //遍歷TreeSet取出其中的元素
        for (String ip : ts) {
            //將每段前面的0去掉
            ip = ip.replaceAll("0*(\\d+)","$1");
            System.out.println("ip = " + ip);
        }

3、對郵件地址校驗

        //對郵件地址校驗
        //匹配規則
        String mail = "[email protected]";
        //是校驗,不是註冊,不用判斷位數
//        String regex = "[a-zA-Z0-9_][email protected][a-zA-Z0-9]+(\\.[a-zA-Z]{1,3}){1,3}";
        //籠統式匹配
        String regex = "\\[email protected]\\w+(\\.\\w+)+";
        boolean b = mail.matches(regex);
        System.out.println("mail : " + b);

注:正則的閱讀性差,而且寫完後還需要不斷地進行驗證。所以,在實際開發中,會將正則的校驗封裝成方法,將需要校驗的字串作為引數傳到方法中進行驗證

相關推薦

37-表示式概述+符號+字串常見操作功能+Pattern+Matcher+練習題

一、正則表示式概述 1、正則表示式:用於操作字串資料,通過一些特定的符號體現 2、String類中 (1)public boolean matches(String regex):告知此字串是否匹配給定的正則表示式。呼叫此方法的str.matches(regex)形式與

表示式的特殊符號

特殊符號 代表意義 [:alnum:] 代表英文大小寫字元及數字,即0~9、A~Z、a~z [:alpha:] 代表任何英文大小寫字元,即A~Z、a~z [

java:表示式概述和簡單使用

public class Demo1_Regex { public static void main(String[] args) { // TODO Auto-generated method

表示式中常用符號

一: 正則在Perl、Py森、Ruby、Java等語言中文字的正則表示式幾乎是一樣的 以前常用到的在網上都有現成的例子拿來用,比如電話格式、郵箱格式之類的。 但是自然語言處理中往往會根據自己的需求來制定一個表示式,如果正則的知識掌握的比較片面,在編寫自然語言

js表示式校驗值是否為一個數字正負整數,正負小數均可校驗

百度了很多給出的正則清一色都是 /^[0-9]+.?[0-9]*$/ 但是經過實測此正則表示式是不完全正確的 所以自己測試並寫了新的校驗是否為數字的正則表示式,經自己測試,正負正數,正負小數均能正確判斷 /(^[\-0-9][0-9]*(.[0-9]+)?

14.01_常見物件(表示式概述和簡單使用)

14.01_常見物件(正則表示式的概述和簡單使用) A:正則表示式 是指一個用來描述或者匹配一系列符合某個語法規則的字串的單個字串。其實就是一種規則。有自己特殊的應用。 作用:比如註冊郵箱,郵箱有使用者名稱和密碼,一般會對其限制長度,這個限制長度的事

關於表示式的一些符號和sed、awk的速查筆記

之前轉載了一篇文章詳細講解正則表示式,傳送門:https://blog.csdn.net/CHEndorid/article/details/82932455,本文針對一些常用的進行梳理,並新增sed、awk簡單的操作,作為一個速查筆記   //裡的就是正則表示式 ^表示行

js 表示式去除html字元中所有的標籤img標籤除外

廢話不多說,直接上程式碼:description.replace(/<(?!img).*?>/g, ""); 如果保留img,p標籤,則為:description.replace(/<

表示式引擎的構建——基於編譯原理DFA龍書第三章——2 構造抽象語法樹

簡要介紹     構造抽象語法樹是構造基於DFA的正則表示式引擎的第一步。目前在我實現的這個正則表示式的雛形中,正則表示式的運算子有3種,表示選擇的|運算子,表示星號運算的*運算子,表示連線的運算子cat(在實際正則表示式中被省去)。 例如對於正則表示式a*b|c,在a*

linux之表示式中特殊符號的含義

廢話不說,直接上圖 萬用字元與正則表示式 容易混淆,首先要明白二者是不同的,個人感覺萬用字元用於Linux的shell命令(如檔名相關操作)中,而正則表示式用於文字內容中的字串

表示式「^」符號的正確理解方式

以上面這個正則表示式為例,一般情況下我們會使用兩種思路去理解 不匹配「a」和「b」開頭的字串 匹配除「a」和「b」以外的所有字串開頭的字串 通過這兩種思路去理解這個正則表示式, 最終的答案都是一樣的,也是正確的。 我們思考問題的邏輯思路更傾向於第一種理解方式。 然而, 對於整套正則表示式

JS表示式之特殊符號

在正則表示式中,許多標點符號具有特殊含義,比較難記,現歸納備個份: 這些符號有:^ $ . * +  - ? = ! : | \ / ( ) [ ] { } 1.“[ ]”表示字元類: 即括號裡是個字符集:如/[abc]/,表示和含有a,b,c任何一個字母的字串都匹配。 注:特殊字元類:\s表示空格符、製表

根據表示式反向生成對應的字串現有工具(包)總結

為什麼會調研這塊知識點?在做測試的時候,資料的自動生成,做自動mock都會用到按規則自動生成資料,所以了~~ 其中有部分是前輩們總結的直接拿來了,多種語言的,但我本身關注更多的是java、python和go,其他語言備用 總結如下: python Exrex, Pyt

js表示式匹配並替換特定字串

var reg=/name="(.*?)\"/gi; // var arr=str.match(reg); // console.log(arr.length) var newStr=str.replace(reg,'name=

c# 用表示式獲取開始和結束字串中間的值

/// <summary> /// 獲得字串中開始和結束字串中間得值 /// </summary> /// <param name="str">字串</param> /// <param name="s">開始</param>

Python中使用中文表示式匹配指定的中文字串

業務場景: 從中文字句中匹配出指定的中文子字串 .這樣的情況我在工作中遇到非常多, 特梳理總結如下. 難點: 處理GBK和utf8之類的字元編碼, 同時正則匹配Pattern中包含漢字,要漢字正常發揮作用,必須非常謹慎.推薦最好統一為utf8編碼,如果不是這種最優情況,也有

jmeter表示式提取器提取特定字串後的全部內容

jmeter進行JDBC請求時,請求後的響應結果在傳遞給下一個請求使用時,需要用到關聯,也在jmeter中,關聯通過正則表示式提取器實現。 但是,在JDBC請求後的響應結果中,往往需要關聯的內容是隻有左

表示式:檢查一個句子或者字串是否以大寫字母開頭,以句號結尾.

正則表示式就是構造一個描述要找文字串的表示式,是一種描述性語言,不是直接給出要找的文字串序列,當然這樣也行。 比如在java中有些正則表示式示例: “the\W+” 表示以the這三個字母開頭然後緊

利用表示式計算含有中文的字串長度

using System;using System.Text.RegularExpressions; namespace LangZi{    /**//// <summary>    /// StringHelper 的摘要說明。    /// </su

表示式 第六篇:呼叫CLR函式執行查詢

正則表示式在文字查詢方面,不管是速度還是功能,都十分強大。雖然SQL Server資料庫可以執行模糊查詢(像like子句)和全文查詢(Fulltext search),但是這兩個子句只能查詢簡單的模式,無法應對複雜的查詢需求。這是因為SQL Server沒有執行正則表示式的內建函式,無法直接執行正則查詢。我們