中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Java API中使用正則表達式

發布時間:2020-11-26 16:49:49 來源:億速云 閱讀:191 作者:Leah 欄目:編程語言

如何在Java API中使用正則表達式?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

一、正則表達式的理論基礎

1、普通字符的表示

我們說正則表達式主要由普通字符和元字符組成,那么我們首先先看看普通字符該如何表示。大部分普通字符由字符本身即可表示,例如:'s','i','n','g','l','e'等。除此之外,也有一些特殊的表示方式。

  • 以/0開頭,后面緊跟1-3位數字,表示的是一個八進制數。這個數的十進制值對應于ASCII編碼中的相應字符。

  • 以/x或者/X開頭,后面緊跟兩位字符,表示的是一個十六進制的數。該數的十進制的值對應于ASCII編碼中相應的字符。

  • 以/u開頭,后面緊跟四位字符,表示一個Unicode編號。該編號對應于Unicode字符集中的一個具體字符。

  • 另外還有一些元字符,雖然它們具有特殊的含義,但是往往在某種特殊情況下,需要將這些元字符當做普通字符使用,我們使用 '/'+元字符,表示轉移該元字符,此后該元字符將表示一個普通字符。例如:'//','/^',它們分別表示的是 '/'和 '^',不再具有特殊含義了。下面我們開始逐漸介紹正則表達式語法中的元字符的特殊含義。

2、字符組匹配單個字符

我們用一對中括號([.....])表示字符組,整個字符組中會有多個字符位列其中,該字符組表示的含義是:匹配任意一個字符,該字符是位列字符組中的。例如: [single]匹配的是字符's','i','n','g','l','e'中的任意一個字符。以上我們簡單介紹了字符組的基本概念以及它所能匹配的內容,其實有時候為了表述連續的字符,我們會結合元字符 '-' 一起來操作字符組。例如:[0123456789],匹配的是0到9之間的任意一個數字,對于這種情況我們可以選擇這樣來簡化操作:[0-9]。其實兩者表述的含義是一樣的,為了簡化起見,如果遇到連續的字符表述,可以選擇使用元字符來簡化。同樣的還有[a-z],它匹配任意一個小寫字母。對于元字符 '-' 還需要說明一點的是:該字符只有出現在兩個字符之間才具有特殊含義,單獨出現在字符組的所有字符之前或者之后只能表述普通字符 '-' 。下面介紹有關字符組的一些其他相關的元字符。

元字符 '^' 表示排除的意思,和元字符 '-' 類似,只有放在所有字符的最前面才具有特殊含義,否則只能表示普通字符。例如: [^1234] ,該字符組匹配一個字符,但是不是1或2或3或4。當然, [c^yy] ,匹配的是四個普通字符,'c','^','y','y'。此外,需要注意一點的是,除了以上介紹的幾種元字符必須置放于指定位置上才能起作用以外,其余所有元字符在字符組中統統被視作普通字符,不再具有特殊含義。

除此之外,字符組還支持嵌套使用。例如: [0-9[a-z]] ,該字符組匹配一個數字或者一個字母。我們也可以使用&&加強限定規則。例如: [0-9&&[^0123]] ,該字符組匹配的是0到9之間任意一個數字,但是該數字不能是0到3中任意一個,也就是只能匹配4到9之間任意一個數字。最后和字符組有關的內容還是涉及一個預定義字符組,所謂預定義字符組就是對字符組的適當封裝,對于一些簡單的組合使用簡介的調用方式。例如:

      ?\d:等同于字符組 [0-9],表示任意一個數字字符

      ?\w:較為常見,等同于字符組[0-9a-zA-Z],表示任意一個world(單詞字符)

      ?\s:等同于[ \t\n\x0B\f\r] ,匹配的是一個空格字符(space)

當然,它們也有相對應的大寫形式,但是表示的意思卻是截然相反的。

      ?\D:等同于[^0-9] ,表示一個任意非數字字符

      ?\W:等同于[^0-9a-zA-Z] ,表示任意一個非單詞字符,往往會是一些特殊符號

      ?\S:等同于[^\t\n\x0B\f\r] ,匹配一個任意非空格的字符

3、用于指定字符多次出現的量詞

所謂的量詞主要是三個元字符,它們主要用于指定量詞前面的字符在匹配時可以多次出現,具體區別接下來會介紹。首先我們需要知道,這三個元字符是:+ ,*, ?。下面描述它們各自作用及相互之間的區別:

      ?+:該元字符指定位于元字符前面的普通字符可以出現一次或者多次。例如:se+cyy這個正則表達式,字符secyy,seeeecyy都是可以匹配的,但是scyy是不能匹配的,前面的字符是必須出現的。

      ?*:該元字符指定位于元字符前面的普通字符可以出現零次或多次。例如:
se*cyy

對于該正則表達式而言,secyy,seecyy都是可匹配的,并且scyy也是可以匹配的。這就是和元字符 + 的簡單區別。

      ??:該元字符指定位于元字符前面的普通字符可以出現也可以不出現,但是不能多次出現。例如:se?cyy,對于該正則表達式,secyy,scyy等都是可匹配的,但是seeeecyy則是不能匹配的。它指定你前面的一個字符要么出現,要么不出現,不允許多次出現。

在這里我們要申明一個誤區,這里的三個元字符量詞作用的是緊鄰該元字符前面的一個字符,并不是作用與元字符前面所有的字符,這里是需要注意的,包括筆者當初也都是誤以為此的。

以上我們介紹了簡單量詞的概念,但是它們只能用于表示模糊的次數。可以出現多次,但是多次是多少卻沒有定論。對于要求字符出現精確次數的情況,我們可以使用通用量詞來解決。{m,n}是通用量詞的最基本形式,它指定前面的字符出現的次數在m到n之間。

看幾個例子:

      ?se{0,10}cyy:其中e可以出現0-10次

      ?se{9}cyy:其中e必須出現9次

      ?se{0,}cyy:其中e可以出現0-無窮大次,等同于se*cyy。

4、分組劃分組別

在介紹分組之前,無論是使用量詞還是字符組都是針對的一個字符。而分組針對的就是一串字符,我們也可以對分組使用量詞,控制該分組出現的次數。我們使用()括號表示分組,例如:

sing(le)de(cyy

其中le和cyy分別是一個分組,對于一個完整的正則表達式,從頭開始,每個分組都是有編號的,按照出現的次序,以1為基數遞增。至于為什么要有編號,下文說。對于分組我們依然是可以使用量詞控制其出現次數的,例如:

sing(le)+cccc:在該正則表達式中,分組le可以出現一次或者多次
sing(le)*cccc:在該正則表達式中,分組le可以出現零次或者多次

結合元字符 '| ',可以實現和字符組一樣的功效,例如:

(happy|cyy|single)

該正則表達式可以匹配三個字符子串,happy,cyy,single。但是這里需要注意的是,元字符 | 如果用于字符組中就不再具有特殊含義,將會被作為普通字符來匹配。(這一點其實在介紹字符組的時候已經強調過)

下面解決一個上文遺留問題,分組的編號到底有什么作用。為分組編號其實是為了重新捕獲和使用分組,每個分組按照出現的次序從1開始遞增,我們使用 +分組編號進行引用。

例如:

<(\w+)>(.*)</\1>:該正則表達式等效于:<(\w+)>(.*)</\w+>

(\w+)表示任意個字符(字母或數字),(.*)表示任意的符號,\1則引用了分組(\w+)。所以在這里,html中所有非單標簽元素都是能匹配的。當然,如果我們不想使用默認的編號來引用分組,我們其實也是可以在定義分組的時候為分組命名。為分組命名的語法格式為: (?<name>X) ,引用分組的語法格式為: \k<name> 。例如:

<(?<num1>a)>(.*)</\k<num1>>:等效于:<a>(.*)</a>

上述正則表達式定義了一個名為num1的分組,并后續進行了引用。下面介紹正則表達式的最后一塊理論基礎,邊界匹配。

5、邊界匹配

以上我們所介紹的所有內容主要還是針對單個字符或者多個字符組成的分組,我們可以限制他們的出現次數以及出現位置等。但是其實在正則表達式中,我們也是可以限制邊界必須滿足某種條件的。主要涉及的元字符有:^, $, \A, \Z, \z和\b。

首先看元字符 ^ ,在字符組中,該元字符表示否定的意思,此處匹配正則表達式首部位置邊界。例如: ^abc匹配一個以abc開頭的字符串。

元字符 $匹配的字符串的尾部邊界,它規定被匹配的字符串必須以什么結束。例如:

abc$:dabc,abc,abc/n都是可匹配的

實際上,如果被匹配字符串是以指定字符結尾或者指定字符之后跟換行符,都是可匹配的。此處需要注意尾部邊界匹配時的表述格式。(不同于首部匹配)

\b匹配的是單詞邊界,所謂的單詞邊界指的就是:當一邊是字符,一邊是非字符的時候,此處即為單詞邊界。也就是單詞結束的那個位置。還有一些邊界,例如:\A,\b,\Z等,各自匹配的邊界如下圖所示;

如何在Java API中使用正則表達式

當然,對于邊界匹配最通用的一種方式就是環視。它不局限于整個表達式的開頭和結尾,它可以出現在表達式中的任何位置,既可以向前匹配,也可以向后匹配。主要分為以下四種情況:

       ?肯定順序環視:它要求表達式的右邊字符串必須滿足某種約定,語法(?=....) 。例如:single(?=cyy) ,字符e的右邊即為邊界并且要求必須為cyy,所以該表達式只能匹配singlecyy。

       ?否定順序環視:它要求表達式的右邊字符串必須不能滿足某種約定,和上一中情況是相反的,語法格式為:(?!...)。

       ?肯定逆序環視:它要求表達式的左邊必須滿足某種約束,語法格式為:(?<=...)

       ?否定逆序環視:它要求表達式的左邊必須不能滿足某種約束,語法格式為:(?<!...) 。(此處為了消除!在MarkDown編輯器中的特殊樣式,加了空格,望讀者注意)

雖然看起來有四種不同的環視類型,但是實際上分為兩種,一種是向左看,一種是向右看。以上有關正則表達式的基本內容大致介紹完結,下面主要看看如何在Java中驗證我們上述的這些理論。

二、Java API對正則表達式的支持

在Java中,對正則表達式的支持,主要還是java.util.regex這個包,我們常用的是其中的Pattern和Matcher這兩個類。其中Pattern綁定了一個正則表達式,也就是代表了一個規則,Matcher綁定了一個Pattern和一個被處理的字符串,我們可以利用Matcher中的一些方法來完成匹配工作。此外,Java中所有的正則表達式都是以字符串的形式出現的,所以自然離不開String這個類,該類中的很多方法的參數都是基于正則表達式的,下文將詳細介紹。我們首先看Pattern這個類。

Pattern主要用于編譯一個正則表達式,也就是創建一個Pattern對象,該對象與實際的一個正則表達式想綁定,它僅僅代表一個規則,與實際要匹配的字符串無關。

例如:

String str = "//w";
Pattern p = Pattern.compile(str);

Pattern的compile方法將str這個正則表達式編譯成一種內部結構,然后以Pattern實例的形式返回,至于這種內部結構是什么樣子的,此處暫時不涉及。我們只需要知道,此時返回的pattern實例是綁定了一個正則表達式的。當然,Pattern還有一個compile重載,可顯式指定匹配模式。

public static Pattern compile(String regex, int flags) {
 return new Pattern(regex, flags);
}

此處主要有四種匹配模式可選,單行模式,多行模式,無視大小寫模式,無視元字符模式(該模式下,所有元字符將會失效)。各自對應的常量:Pattern.DOTALL,Pattern.MULTILINE,Pattern.CASE_INSENSITIVE,Pattern.LITERAL。這些常量的值如下:

public static final int DOTALL = 0x20;(32)
public static final int MULTILINE = 0x08;(8)
public static final int CASE_INSENSITIVE = 0x02;(2)
public static final int LITERAL = 0x10;(16)

當然,我們沒必要記住他們各自所對應的常量的值,在使用的時候直接調用它們的常量名即可。下面通過介紹String的幾個基本方法,了解正則表達式在Java中的基本使用情況。

首先我們看split方法,該方法用于分割字符串,返回一個String數組。

public String[] split(String regex, int limit)

第一個參數接受的是一個正則表達式,第二參數用于限定分割次數。其實從其源代碼中我們大致可以知曉該方法作用原理:首先利用indexOf方法找到分割符首次出現的位置,將該位置以前所有字符保存,拿到剩余子串的所有內容,一樣的操作。最后得到的數組就是按照分隔符分割的結果。limit只不過強制限定了分割次數,達到次數上限,即使后面仍有分隔符可匹配,也選擇放棄。(打包后面所有內容為一個分組),看個例子:

public static void main(String [] args){
 String str = "cyy,single.abc/https";
 String[] results = str.split("[,./]");
 for(String s : results){
 System.out.print(s+" ");
 }
}

輸出結果:cyy  single  abc  https

此處有人可能會有疑問,說好的Pattern和Matcher才是正則表達式的主要操作類,怎么沒見到他們。其實在split內部調用的就是Pattern的相關方法。

return Pattern.compile(regex).split(this, limit);

這是String類中split方法的最后一行代碼,String中的split方法除了最后一行代碼,其余代碼處理的都是regex為普通單個字符的情況,而對于多個字符乃至包含元字符的時候都是由Pattern中split方法處理的,該方法中會創建Matcher類并調用其中find等方法進行匹配查找,代碼量比較多,此處不再贅述。

下面看String的一個匹配校驗的方法。

public boolean matches(String regex) {
 return Pattern.matches(regex, this);
}

顯然,該方法內部調用的是Pattern的matches方法,

public static boolean matches(String regex, CharSequence input) {
 Pattern p = Pattern.compile(regex);
 Matcher m = p.matcher(input);
 return m.matches();
}

這是一個非常標準的對正則表達式的處理流程,首先編譯(綁定)正則表達式字符串獲取Pattern實例,然后調用Pattern的matcher方法獲取Matcher實例,接著就可以利用Matcher實例完成大量工作。此處調用matches方法完成對已綁定的正則表達式和預處理字符串的匹配工作,返回值為boolean。

最后看String的ReplaceAll方法:

public String replaceAll(String regex, String replacement) {
 return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

該方法實際上還是依賴的Matcher中的replaceAll方法,由于一個Matcher實例是同時綁定一個正則表達式和一個被匹配字符串的。所以在Matcher內部的replaceAll方法在進行搜索匹配的時候就無需傳入額外參數。具體代碼,大家可以自行查看,此處節約篇幅不再贅述。

三、常見正則表達式的案例

接下來我們主要從日常較為普遍使用的一些案例中來深刻理解上述所有內容。

1、Email地址

通常我們的Email地址的格式主要是:

       ?3-18字符,可使用英文、數字、減號、點或下劃線

       ?必須以英文字母開頭,必須以英文字母或數字結尾

       ?點、減號、下劃線不能連續出現兩次或兩次以上

以上是騰訊QQ郵箱的要求,相對而言已算是較為復雜,接下來我么看如何實現它。首先,第一條要求:

[-._a-z0-9A-Z]{3,18}

滿足第二條要求:

[a-zA-Z][-._a-z0-9A-Z]{1,16}/w

滿足第三個條件:

(?![-0-9a-zA-Z._]*(--|\.\.|__))[a-zA-Z][-._a-z0-9A-Z]{1,16}/w

至于最后一個條件的匹配,我們使用否定順序環視來實現,它要求右邊界所有內容不能是如下的形式:0個或者多個(英文、數字、減號、點或下劃線)加上兩個連續減號或者點或者下劃線。也就是說,右邊如果由多個字符或者一個減號,點或者下劃線,那是沒事的,可一旦出現連續的減號,點或者下劃線,那么就將立馬被否定順序環視匹配,進而不滿足條件結束。

其實上述對郵箱用戶名的匹配算是比較嚴格的,一般用于匹配郵箱用戶名的正則表達式則沒這么嚴格,具體要求如下:

      ?由英文字母、數字、下劃線、減號、點號組成

      ?至少1位,不超過64位

      ?開頭不能是減號、點號和下劃線

由于比較簡單,此處直接寫出結果:

[^-._][-._a-zA-Z0-9]{0,63}

2、手機號碼

在看一個手機號碼的正則表達式匹配情況,具體要求如下:

      ?中國的手機號碼都是11位數字

      ?目前手機號第1位都是1,第2位取值為3、4、5、7、8之一

最終的表述結果為:

1[34578][0-9]{9}

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

平果县| 祁连县| 桂东县| 丰镇市| 农安县| 抚顺县| 威宁| 精河县| 晴隆县| 龙陵县| 青岛市| 西乌| 克东县| 澎湖县| 衡东县| 阜新| 兴和县| 远安县| 加查县| 邢台市| 河南省| 宣汉县| 陇川县| 扎囊县| 聂荣县| 台江县| 凤阳县| 西平县| 沭阳县| 冀州市| 江油市| 鱼台县| 大渡口区| 德化县| 逊克县| 宽甸| 宜春市| 集贤县| 台江县| 公主岭市| 青铜峡市|