Java與正則表達式

jopen 8年前發布 | 19K 次閱讀 Java開發

Java與正則表達式
</h1>

標簽: Java基礎


正則

正如正則的名字所顯示的是描述了一個規則, 通過這個規則去匹配字符串. 學習正則就是學習正則表達式的語法規則


正則語法

普通字符

字母, 數字, 漢字, 下劃線, 以及沒有特殊定義的標點符號都是普通字符. 表達式中的普通字符在匹配一個字符串時, 匹配與之相同的一個字符.


轉義字符

字符 解釋
\n 換行符
\t 制表符
\^ \$ \( \) \{ \} \? \+ \* | \\ \[ \] 匹配這些字符本身

標準字符集合

字符 匹配
\d 任意一個數字
\w 任意一個字母/數字/下劃線
\s 任意一個空格/制表符/換行符等空白字符
. 小數點在內的任意一個字符(除\n外)
[\s\S] 匹配\n在內的任意一個字符
  • 注意大小寫: 大寫是取反

自定義字符集合

[] 方括號匹配方式, 能夠匹配方括號中的任意一個字符.

表達式 解釋
[ab5@v] 匹配a b 5 @ v中任意一個
[^ab5@v] 匹配a b 5 @ v之外任意一個
[f-k] 匹配f-k之間任意一個字母
[^f-k] 匹配f-k之外任意一個
[f-k0-3] 匹配f-k0-3之間任意一個字母
[^f-k0-3] 不匹配f-k0-3之間任意一個字母

注:

  • 正則表達式中的特殊符號, 被包含到[]中, 則失去特殊意義, 除了- ^之外.
    • []中的^表示取反的含義.
    • []中的-表示范圍的含義
  • 標準字符集合(除小數點外),如果被包含于中括號中,則自定義集合將包含該集合.
    [\d.\-+]將匹配: 數字, 小數點, -, +

量詞

量詞 解釋
{n} 表達式重復n次
{m,n} 表達式至少重復m次,最多重復n次
{m,} 表達式至少重復m次
? 匹配表達式0次或者1次
+ 表達式至少出現1次,相當于 {1,}
* 表達式不出現或出現任意次,相當于 {0,}
  • 貪婪模式與非貪婪模式
    貪婪模式: 匹配字符越多越好, 默認.
    非貪婪模式: 匹配字符越少越好, 需要在量詞后再加上一個?.

  • 示例

    • 匹配手機號1[358]\d{9}
    • 匹配郵箱 ([\w\-\.]+)@([0-9a-zA-Z\-]+)(\.[a-zA-Z]{2,4}){1,2}

字符邊界

零寬匹配: 匹配的不是字符而是位置(符合某種條件的位置),不匹配任何字符.

字符 解釋
^ 與字符串開始的地方匹配
$ 與字符串結束的地方匹配
\b 匹配一個單詞邊界,也就是單詞和空格之間的位置

注: \b會匹配這樣一個位置: 前面的字符與后面的字符不全是\w


選擇符與分組

表達式 解釋
| 左右兩邊表達式之間 “或” 關系,匹配左邊或右邊
() 捕獲組 被修飾時,()中的表達式可以作為整體被修飾; 取匹配結果時, ()中的表達式匹配到的內容可以被單獨得到; 每一對括號會被分配一個編號(以(為準,從左到右: 從1開始)
(?:exp) 非捕獲組 一些表達式中, 不得不使用(), 但又不需保存()中子表達式匹配的內容, 這時可以使用非捕獲組來抵消()帶來的副作用

注: 非捕獲組可以用于當處理大量文本時用于優化內存分配.

  • 反引用\nnn
    由上面可知, 捕獲組默認被分配了編號, 通過反向引用, 可以對分組已捕獲的字符串進行引用
  • 示例
    (\w{2})\1 匹配類似toto dodo gogo這樣由一個單詞復制而來得到的字符串
    (img)\w+\1 匹配前后都是img的字符串

零寬斷言(預搜索)

  • 零寬度: 只進行子表達式的匹配, 匹配內容不計入最終的匹配結果.
  • 位置匹配: 判斷當前位置的前后字符是否符合指定的條件, 但不保留前后的字符.

正則表達式中, 如果子表達式匹配到得是字符內容, 而非位置, 并被保留到最終的匹配結果中, 那么就認為這個子表達式是占有字符的; 如果子表達式匹配的僅僅是位置, 或者匹配的內容并不保存到最終的匹配結果中, 那么就認為這個子表達式是零寬度的(占有字符或零寬度, 是針對匹配的內容是否保留到最終結果而言的)

表達式 解釋
(?=exp) 斷言自身出現的位置的后面能夠匹配表達式exp
(?!exp) 斷言自身出現的位置的后面不能匹配表達式exp
(?<=exp) 斷言自身出現的位置的前面能夠匹配表達式exp
(?<\!exp) 斷言自身出現的位置的前面不能匹配表達式exp
  • 示例
    [a-z]+(?=ing) 匹配所有以ing結尾的單詞, 但ing并不放入字符串
    [a-z]+(?=\d+) 匹配所有以數字結尾的單詞
    [a-z]+(?!\d+) 匹配不以數字結尾的單詞
    (?<=(href=\")) 匹配以href="開頭的字符串

Java Pattern與Matcher

  • java.util.regex包下提供的PatternMatcher兩個類提供了在Java中的正則支持;
  • Pattern對象是正則表達式編譯后在內存中的表現形式, 因此, 正則表達式字符串必須先被編譯為Pattern對象Pattern pattern = Pattern.compile("\\w+");然后再利用該Pattern對象創建對象的Matcher對象Matcher matcher = pattern.matcher(input);.
  • Matcher對象是一個對CharSequence執行匹配操作的正則引擎: 執行匹配所涉及的狀態保留在Matcher對象中, 多個Matcher對象可共享同一個Pattern對象.
/**
 * Created by jifang on 15/12/15.
 */
public class LearnRegexp {

    @Test
    public void testSearch() {
        String input = "hello1997&&2000";

        // 將一個正則表達式編譯成Pattern對象
        Pattern pattern = Pattern.compile("\\w+");
        Matcher matcher = pattern.matcher(input);

        // matches嘗試將整個字符序列與該模式匹配
        System.out.println(matcher.matches());

        // reset將matcher中的指針重新定位
        matcher.reset();
        // find 方法掃描整個字符串, 查找能否找到下一個符合該模式字符串
        while (matcher.find()) {
            String group = matcher.group();
            System.out.println(group);
        }
    }

    /**
     * 將所有的數字都替換成'#'
     */
    @Test
    public void testReplace() {
        String input = "1j2h3h4g5o";
        Matcher replace = Pattern.compile("[0-9]").matcher(input);
        input = replace.replaceAll("#");
        System.out.println(input);
    }

    /**
     * 將字符串按數字分割
     */
    @Test
    public void testSplit() {
        String input = "1j24h356h467g589o";
        String[] strings = input.split("\\d+");
        for (String str : strings) {
            System.out.println(str);
        }
    }
}

由上例可以看到: 其實String中某些方法也支持正則表達式, 如split, replace等(Pattern,Matcher與String的其他用法請參考JDK文檔).

小實驗-抓取網頁中所有的超鏈接

/**
 * 模仿網絡爬蟲, 抓取網站html, 將里面所有的超鏈接都分析出來
 * Created by jifang on 15/12/15.
 */
public class HtmlAnalyzer {

    private final String FILE_PATH = "/Users/jifang/save.txt";

    @Test
    public void client() throws IOException {
        String html = downloadHtml("http://www.163.com/", "gbk");
        // (?<=(href=\"))(?:[\w.\/\:\?\=\&]+)(?=\")  匹配url的正則
        Set<String> urlSet = analyzeHtml(html, "(?<=(href=\\\"))(?:[\\w.\\/\\:\\?\\=\\&]+)(?=\\\")");
        saveToFile(urlSet);
        System.out.println();
    }

    private String downloadHtml(String url, String charset) throws IOException {
        URL readUrl = new URL(url);
        BufferedReader reader = new BufferedReader(new InputStreamReader(readUrl.openStream(), charset));
        return CharStreams.toString(reader);
    }

    private Set<String> analyzeHtml(String html, String regex) {

        Set<String> urlSet = new HashSet<>();
        // 匹配url的正則表達式
        Matcher matcher = Pattern.compile(regex).matcher(html);
        while (matcher.find()) {
            String group = matcher.group();
            urlSet.add(group);
        }

        return urlSet;
    }

    private void saveToFile(Set<String> urlSet) throws IOException {
        PrintStream printer = new PrintStream(new FileOutputStream(FILE_PATH));
        for (String url : urlSet) {
            printer.println(url);
        }
        printer.flush();
        printer.close();
    }
}
  • 附- 運行上程序需要在pom.xml中添加以下依賴
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>

推薦幾個正則驗證工具:


參考

來自: http://blog.csdn.net/zjf280441589/article/details/50450169

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!