在Java中使用正則表達式

我對正則表達式的理解

正則表達式Regex(Regular Expression),是一種通過定義由特定字符組成的表達式來對字符串進行匹配、查找、替換和切割的字符串操作工具蓉坎。

正則表達式中特定的一些字符

表達式 匹配內容
字符
x 字符 x
\\ 反斜線字符
\0n 帶有八進制值 0 的字符 n (0 <= n <= 7)
\0nn 帶有八進制值 0 的字符 nn (0 <= n <= 7)
\0mnn 帶有八進制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)
\xhh 帶有十六進制值 0x 的字符 hh
\uhhhh 帶有十六進制值 0x 的字符 hhhh
\t 制表符 ('\u0009')
\n 新行(換行)符 ('\u000A')
\r 回車符 ('\u000D')
\f 換頁符 ('\u000C')
\a 報警 (bell) 符 ('\u0007')
\e 轉義符 ('\u001B')
\cx 對應于 x 的控制符
字符類
[abc] a胡嘿、b 或 c(簡單類)
[^abc] 任何字符蛉艾,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z衷敌,兩頭的字母包括在內(范圍)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d勿侯、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](減去)
[a-z&&[^m-p]] a 到 z缴罗,而非 m 到 p:[a-lq-z](減去)
預定義字符類
. 任何字符(與行結束符可能匹配也可能不匹配)
\d 數字:[0-9]
\D 非數字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 單詞字符:[a-zA-Z_0-9]
\W 非單詞字符:[^\w]
邊界匹配器
^ 行的開頭
$ 行的結尾
\b 單詞邊界
\B 非單詞邊界
\A 輸入的開頭
\G 上一個匹配的結尾
\Z 輸入的結尾助琐,僅用于最后的結束符(如果有的話)
\z 輸入的結尾
Greedy數量詞
X? X,一次或一次也沒有
X* X面氓,零次或多次
X+ X兵钮,一次或多次
X{n} X,恰好 n 次
X{n,} X舌界,至少 n 次
X{n,m} X掘譬,至少 n 次,但是不超過 m 次

正則表達式在Java中的表現形式

public final class Pattern
extends Object
implements Serializable

Pattern正則表達式的編譯表示形式呻拌。

指定為字符串的正則表達式必須首先被編譯為此類的實例葱轩。然后,可將得到的模式用于創(chuàng)建 Matcher 對象藐握,依照正則表達式靴拱,該對象可以與任意字符序列匹配。執(zhí)行匹配所涉及的所有狀態(tài)都駐留在匹配器中猾普,所以多個匹配器可以共享同一模式袜炕。

因此,典型的調用順序是

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

在僅使用一次正則表達式時抬闷,可以方便地通過此類定義 matches 方法妇蛀。此方法編譯表達式并在單個調用中將輸入序列與其匹配。語句

 boolean b = Pattern.matches("a*b", "aaaaab");

等效于上面的三個語句笤成,盡管對于重復的匹配而言它效率不高评架,因為它不允許重用已編譯的模式。

使用正則表達式對字符串進行匹配

使用正則表達式對字符串進行匹配有三種方式:
1)使用字符串的對象的matches()方法
2)使用Matcher的對象的matches()方法
3)使用Pattern類的matches()方法
匹配的特點:
1)根據正則表達式的規(guī)則對整個字符串進行匹配
2)匹配結果返回對應的布爾值
使用方法:
請參考下面匹配字符串是否為電話號碼的實例

public class MatchTest {

    public static void main(String[] args) {
        System.out.println("一炕泳,使用字符串的對象的matches()方法");
        matchDemo_1("13805646681");
        matchDemo_1("03805646681");
        matchDemo_1("13805Jia681");
        matchDemo_1("138056");

        System.out.println("二纵诞,使用Matcher的對象的matches()方法");
        matchDemo_2("13805646681");
        matchDemo_2("03805646681");
        matchDemo_2("13805Jia681");
        matchDemo_2("138056");

        System.out.println("三,使用Pattern類的matches()方法");
        matchDemo_3("13805646681");
        matchDemo_3("03805646681");
        matchDemo_3("13805Jia681");
        matchDemo_3("138056");
    }

    /**
     * 匹配字符串是否為電話號碼
     * 匹配規(guī)則:
     * 1.電話號碼以數字1開頭
     * 2.電話號碼長度為11
     * 3.電話號碼為全數字
     * 對應的正則表達式:
     * 1)"1\\d{10}"
     * 解讀:
     *      正則表達是第一個數是1培遵,所以它只能匹配以1開頭的字符串浙芙;
     *      \\d,因為Java中反斜杠會把它后面的字符進行轉移籽腕,所以\\d就是正則表達式中預定義字符類中的\d(== [0-9]),即能夠匹配數字0-9中的任意一個嗡呼;
     *      {10},代表前面的\d恰好出現10次皇耗,這樣加上第一個數1共有11個數字南窗,所以它只能匹配長度為11且全部為數字的字符串。
     * 2)"1[0-9]{10}"
     * 解讀:
     *      \d == [0-9]
     */
    public static void matchDemo_1(String str) {
        String regex = "1\\d{10}";
        boolean isMatched = str.matches(regex);
        System.out.println(str + (isMatched ? "是電話號碼" : "不是電話號碼"));
    }

    public static void matchDemo_2(String str) {
        String regex = "1[0-9]{10}";
        // 1郎楼,將正則表達式編譯成Pattern對象
        Pattern p = Pattern.compile(regex);
        // 2, 與字符串進行關聯(lián)万伤,生成Matcher對象
        Matcher m = p.matcher(str);
        // 3,對字符串進行操作
        boolean isMatched = m.matches();
        System.out.println(str + (isMatched ? "是電話號碼" : "不是電話號碼"));
    }

    public static void matchDemo_3(String str) {
        String regex = "1\\d{10}";
        boolean isMatched = Pattern.matches(regex, str);
        System.out.println(str + (isMatched ? "是電話號碼" : "不是電話號碼"));
    }
}

使用正則表達式對字符串進行替換

正則表達式既可以替換字符串中所有匹配到的字符呜袁,也可以只替換第一次匹配到的字符敌买,對應的兩個方法是replaceALL和replaceFirst,同樣在String對象和Matcher對象中都包含這兩個方法。
替換的特點:
1)可以將正則表達式匹配到的字符(串)替換為你指定的字符(串)
2)替換結果生成新的字符串
使用方法:
請參考下面疊詞替換的實例

public class StackedWordsReplace {
    public static void main(String[] args) {
        stackedWordsReplaceDemo_1();
        stackedWordsReplaceDemo_2();
    }

    public static void stackedWordsReplaceDemo_1() {
        // 將下面的字符串轉換成"我要學習編程阶界。"
        String str = "我我我我我要要學學學編編編編程程程程虹钮。";

        // 正則表達式中通過()創(chuàng)建一個捕獲組
        // 捕獲組默認從1開始進行編號,可以通過從左到右計算開括號(左括號)個數和順序進行排序
        // 例如膘融,在表達式 ((A)(B(C))) 中芜抒,存在四個這樣的組:((A)(B(C)))、(A)托启、(B(C))宅倒、(C)
        // 正則表達式中的\n和$n分別在匹配環(huán)節(jié)和替換環(huán)節(jié)中引用捕獲組捕獲的內容,n代表數字1屯耸、2拐迁、3...
        // "(.)\1+"解讀:
        // .可以匹配任意字符,\\1即\1引用(.)的捕獲內容,+前面的字符出現一次或多次疗绣。
        // 比如,當.匹配的到我的時候\1就是我线召,所以這個表達式能夠匹配到無數個我連續(xù)組成但最低不少兩個我的字符串。
        // $1為替換的類容多矮,因為$1引用(.)的捕獲內容缓淹,所以當.匹配到什么就替換為什么
        str = str.replaceAll("(.)\\1+", "$1");

        System.out.println(str);
    }

    public static void stackedWordsReplaceDemo_2() {
        String str = "我我我我我要要學學學編編編編程程程程哈打。";
        String regex = "(.)\\1+";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(str);
        str = matcher.replaceAll("$1");
        System.out.println(str);
    }
}

使用正則表達式對字符串進行切割

使用正則表達式對字符串進行切割有兩種方式:
1)使用String對象的split方法
2)使用Pattern對象的split方法
切割的特點:
1)可以將正則表達式匹配到的字符(串)作為分隔符來對字符串進行切割
2)切割結果為子串組成的字符串數組
使用方法:
請參考下面的切割實例

public class SplitTest {
    public static void main(String[] args) {
        splitDemo_1();
        splitDemo_2();
    }

    public static void splitDemo_1() {
        // 將下面的字符串以.為分隔符進行切割
        // 由于在正則表達式中.為預定義字符,所以需要用\進行轉義讯壶,
        // 在Java中\(zhòng)也是轉義字符料仗,所以仍需要進行轉義
        String str = "我.愛.中.國";
        String regex = "\\.";
        String[] strings = str.split(regex);
        for (String s : strings) {
            System.out.println(s);
        }
    }

    public static void splitDemo_2() {
        String str = "我.愛.中.國";
        String regex = "\\.";
        Pattern pattern = Pattern.compile(regex);
        String[] strings = pattern.split(str);
        for (String s : strings) {
            System.out.println(s);
        }
    }
}

綜合案例演示

下面將演示綜合使用和切割來對IP地址進行排序

public class IPSort {

    public static void main(String[] args) {
        ipSort();
    }

    /**
     * 將IP地址進行排序
     */
    public static void ipSort() {
        String ip = "127.0.0.1 192.168.0.1 114.114.114.114 8.8.8.8 10.2.33.134 255.255.255.255";

        // 1.將IP地址全部替換為xxx.xxx.xxx.xxx樣式
        ip = ip.replaceAll("\\w{1,3}", "00$0"); // 將IP地址每一段都添加00
        System.out.println(ip);
        ip = ip.replaceAll("0*(\\w{3})", "$1"); // 去除每一段多余的0,是每一段只保留三位數字
        System.out.println(ip);

        // 2.對字符串進行排序
        String[] arr = ip.split(" ");
        System.out.println(Arrays.toString(arr));
        Arrays.sort(arr);
        for (String s : arr) {
            // 去除添加的0
            s = s.replaceAll("0*(\\w+)", "$1");
            System.out.println(s);
        }
    }
}

使用正則表達式對字符串進行查找

對字符串進行查找伏蚊,主要用的是Matcher對象的以下方法:
1)find()嘗試查找與該模式匹配的輸入序列的下一個子序列
2)group()返回上一次匹配操作所匹配的輸入子序列
3)reset(CharSequence input)將該模式應用到新的輸入序列
查找的特點:
1)可以將正則表達式匹配到的字符(串)逐個找出來
2)查找結果為一個個匹配的子串
3)必須逐個查找立轧,直接調用group()方法無法得到結果
使用方法:
請參考下面的爬去網頁中的電子郵箱實例

public class FindEmail {

    public static void main(String[] args) {
        findEmail();
    }

    public static void findEmail() {
        // 簡單郵箱匹配規(guī)則
        String reg = "\\w+@\\w+(\\.\\w+)+";
        // 1.將正則表達式編譯成Pattern對象
        Pattern p = Pattern.compile(reg);
        Matcher m = null;
        try {
            URL url = new URL("https://www.douban.com/group/topic/70867518/");
            URLConnection connection = url.openConnection();
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null) {
                // 2.將字符串和Pattern對象進行關聯(lián),生成Matcher對象
                if (m == null) {
                    m = p.matcher(line);
                } else {
                    m.reset(line);
                }
                // 3.通過Matcher對象對字符串進行操作
                while (m.find()) {
                    System.out.println(m.group());
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市躏吊,隨后出現的幾起案子氛改,更是在濱河造成了極大的恐慌,老刑警劉巖比伏,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胜卤,死亡現場離奇詭異,居然都是意外死亡赁项,警方通過查閱死者的電腦和手機瑰艘,發(fā)現死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肤舞,“玉大人紫新,你說我怎么就攤上這事±钇剩” “怎么了芒率?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長篙顺。 經常有香客問我偶芍,道長,這世上最難降的妖魔是什么德玫? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任匪蟀,我火速辦了婚禮,結果婚禮上宰僧,老公的妹妹穿的比我還像新娘材彪。我一直安慰自己,他們只是感情好琴儿,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布段化。 她就那樣靜靜地躺著,像睡著了一般造成。 火紅的嫁衣襯著肌膚如雪显熏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天晒屎,我揣著相機與錄音喘蟆,去河邊找鬼缓升。 笑死,一個胖子當著我的面吹牛蕴轨,可吹牛的內容都是我干的港谊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼尺棋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了绵跷?” 一聲冷哼從身側響起膘螟,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碾局,沒想到半個月后荆残,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡净当,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年内斯,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片像啼。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡俘闯,死狀恐怖,靈堂內的尸體忽然破棺而出忽冻,到底是詐尸還是另有隱情真朗,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布僧诚,位于F島的核電站遮婶,受9級特大地震影響,放射性物質發(fā)生泄漏湖笨。R本人自食惡果不足惜旗扑,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慈省。 院中可真熱鬧臀防,春花似錦、人聲如沸边败。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽放闺。三九已至祟昭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怖侦,已是汗流浹背篡悟。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工谜叹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搬葬。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓荷腊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親急凰。 傳聞我的和親對象是個殘疾皇子女仰,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內容