Java正則表達式(Regular Expression) 郵箱驗證

今天做題用到了正則表達式的內容,雖然很早就聽過正則表達式,但是一直是隻聞其聲,不見其人,所以就着今天碰到,系統的整理一下正則表達式,加深一下自己對於正則的理解。
一、緒論:
在寫程序的過程中,有時會需要匹配、查找、替換或者是判斷字符串的出現情況,而且有時不能用簡單的純編碼方式解決這些問題,這個時候就會想到要正則表達式,無論是Java, PHH, C#, Python, JavaScript, ActionScript, Perl等語言,都提高了強大的正則表達式支持,有的語言的精華就在於字符串處理功能比如Perl。

在Java中,正則表達式也是Java處理字符串,文本的重要工具。
Java對正則表達式的處理集中在以下兩個類:
java.util.regex.Pattern 模式類:用來表示一個編譯過的正則表達式。
java.util.regex.Matcher 匹配類:用模式匹配一個字符串所得到的結果。
二、先看一個簡單的例子:
需求:從字符串:{“_type”:”FQDN”,”_oid”:”51a867e4773da1128b1422ad”} 中取出這段數字:51a867e4773da1128b1422ad
沒有用過正則表達式的程序員可能分爲兩步獲取
1. 用String類的indexOf方法獲取51a867e4773da1128b1422ad的初始位置
2. 用String類的subString方法取出51a867e4773da1128b1422ad
用這種方法的缺點是代碼可閱讀性很差,即我們常說的hard code
如果用正則表達式則可以用以下的方法:
String reg = “[0-9A-Za-z]{24,}”; // appear at least 24 times ^[0-9A-Za-z]{24,}
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {// matcher.matchers() {
String fqdnId = matcher.group();
}
三、一些常見的問題
1. 鎖定模式的應用範圍的 ^ 和 wangsheng:wangsheng;  isJoshWang ”: 結尾一定要由”isJoshWang” 的字符串來結尾;
那麼,
   “^abc$”: 就是要求以abc開頭和以abc結尾的字符串,實際上是隻有abc匹配。

   “notice”: 匹配包含notice的字符串。
用這兩個字符就將模式鎖定在一定範圍裏面。

  1. Java對反斜線的處理問題:
    在其他語言中,\表示要插入一個字符\;
    在Java語言中,\表示要插入正則表達式的反斜線,並且後面的字符有特殊意義。
    在Java正則表達式中,如果要插入一個\字符,則需要在正則表達式中寫成\\,原因是APIDoc定義\表示一個反斜線。
    但是如果在正則表示式中表示回車換行等,則不需要多添加反斜線了。比如回車\r就寫作\r.
  2. 常用的與正則表達式相關的API
    1) Matcher.find():嘗試查找與模式匹配的字符序列的下一個子序列。此方法從字符序列的開頭開始,如果該方法的前一次調用成功了並且從那時開始匹配器沒有被重置,則從以前匹配操作沒有匹配到的第一個字符開始,即如果前一次找到與模式匹配的子序列則這次從這個子序列後開始查找。
    2) Matcher.matchers():判斷整個字符序列與模式是否匹配。
    當連續用Matcher對象檢查多個字符串時候,可以使用Matcher.reset()重置匹配器,放棄其所有顯式狀態信息並將其添加位置設置爲零。或者Matcher.reset(CharSequence input) 重置此具有新輸入序列的匹配器來重複使用匹配器。
    3) 組的概念,這個概念很重要,組是用括號劃分的正則表達式,可以通過編號來引用組。組號從0開始,有幾對小括號就表示有幾個組,並且組可以嵌套,組號爲0的表示整個表達式,組號爲1的表示第一個組,依此類推。
    例如:A(B)C(D)E正則式中有三組,組0是ABCDE,組1是B,組2是D;
    A((B)C)(D)E正則式中有四組:組0是ABCDE,組1是BC,組2是B;組3是C,組4是D。
    int groupCount():返回匹配其模式中組的數目,不包括第0組。
    String group():返回前一次匹配操作(如find())的第0組。
    String group(int group):返回前一次匹配操作期間指定的組所匹配的子序列。如果該匹配成功,但指定的組未能匹配字符序列的任何部分,則返回 null。
    int start(int group):返回前一次匹配操作期間指定的組所匹配的子序列的初始索引。
    int end(int group):返回前一次匹配操作期間指定的組所匹配的子序列的最後索引+1。
    4)匹配的範圍的控制
    最變態的就要算lookingAt()方法了,名字很讓人迷惑,需要認真看APIDoc。
    start() 返回以前匹配的初始索引。
    end() 返回最後匹配字符之後的偏移量。
    public boolean lookingAt()嘗試將從區域開頭開始的輸入序列與該模式匹配。
    與 matches 方法類似,此方法始終從區域的開頭開始;與之不同的是,它不需要匹配整個區域。
    如果匹配成功,則可以通過 start、end 和 group 方法獲取更多信息。
    返回:當且僅當輸入序列的前綴匹配此匹配器的模式時才返回 true。
    5) Pattern標記
    Pattern類的靜態方法
    static Pattern compile(String regex, int flags)
    將給定的正則表達式編譯到具有給定標誌的模式中。
    其中的flags參數就是Pattern標記,這個標記在某些時候非常重要。
    Pattern.CANON_EQ
    啓用規範等價。
    Pattern.CASE_INSENSITIVE
    啓用不區分大小寫的匹配。
    Pattern.COMMENTS
    模式中允許空白和註釋。
    Pattern.DOTALL
    啓用 dotall 模式。
    Pattern.LITERAL
    啓用模式的字面值分析。
    Pattern.MULTILINE
    啓用多行模式。
    Pattern.UNICODE_CASE
    啓用 Unicode 感知的大小寫摺疊。
    Pattern.UNIX_LINES
    啓用 Unix 行模式。
    1. 字符串的替換
      String.replace(char oldChar, char newChar)
      返回一個新的字符串,它是通過用 newChar 替換此字符串中出現的所有 oldChar 而生成的。
      String.replace(CharSequence target, CharSequence replacement)
      使用指定的字面值替換序列替換此字符串匹配字面值目標序列的每個子字符串。
      String.replaceAll(String regex, String replacement)
      使用給定的 replacement 字符串替換此字符串匹配給定的正則表達式的每個子字符串。
      String.replaceFirst(String regex, String replacement)
      使用給定的 replacement 字符串替換此字符串匹配給定的正則表達式的第一個子字符串。
      StringBuffer.replace(int start, int end, String str)
      使用給定 String 中的字符替換此序列的子字符串中的字符。
      StringBuilder.replace(int, int, java.lang.String)
      使用給定 String 中的字符替換此序列的子字符串中的字符。
      Matcher.replaceAll(String replacement)
      替換模式與給定替換字符串相匹配的輸入序列的每個子序列。
      Matcher.replaceFirst(String replacement)
      替換模式與給定替換字符串匹配的輸入序列的第一個子序列。
      5、 字符串的切分
      String[] split(String regex)
      根據給定的正則表達式的匹配來拆分此字符串。
      String[] split(String regex, int limit)
      根據匹配給定的正則表達式來拆分此字符串。
      當然,還有一個StringTokenizer類,可以用來切分字符串,但是現在SUN已經不推薦使用了。轉變下思路,其實用正則表達式也可以達到將字符串切分爲段的目的。

正則表達式語法

字符 說明
\ 將下一字符標記爲特殊字符、文本、反向引用或八進制轉義符。例如,”n”匹配字符”n”。”\n”匹配換行符。序列”\”匹配”\”,”(“匹配”(“。
^ 匹配輸入字符串開始的位置。如果設置了 RegExp 對象的 Multiline 屬性,^ 還會與”\n”或”\r”之後的位置匹配。
$ 匹配輸入字符串結尾的位置。如果設置了 RegExp 對象的 Multiline 屬性,$ 還會與”\n”或”\r”之前的位置匹配。
* 零次或多次匹配前面的字符或子表達式。例如,zo* 匹配”z”和”zoo”。* 等效於 {0,}。
+ 一次或多次匹配前面的字符或子表達式。例如,”zo+”與”zo”和”zoo”匹配,但與”z”不匹配。+ 等效於 {1,}。
? 零次或一次匹配前面的字符或子表達式。例如,”do(es)?”匹配”do”或”does”中的”do”。? 等效於 {0,1}。
{n} n 是非負整數。正好匹配 n 次。例如,”o{2}”與”Bob”中的”o”不匹配,但與”food”中的兩個”o”匹配。
{n,} n 是非負整數。至少匹配 n 次。例如,”o{2,}”不匹配”Bob”中的”o”,而匹配”foooood”中的所有 o。”o{1,}”等效於”o+”。”o{0,}”等效於”o*”。
{n,m} m 和 n 是非負整數,其中 n <= m。匹配至少 n 次,至多 m 次。例如,”o{1,3}”匹配”fooooood”中的頭三個 o。’o{0,1}’ 等效於 ‘o?’。注意:您不能將空格插入逗號和數字之間。
? 當此字符緊隨任何其他限定符(*、+、?、{n}、{n,}、{n,m})之後時,匹配模式是”非貪心的”。”非貪心的”模式匹配搜索到的、儘可能短的字符串,而默認的”貪心的”模式匹配搜索到的、儘可能長的字符串。例如,在字符串”oooo”中,”o+?”只匹配單個”o”,而”o+”匹配所有”o”。
. 匹配除”\r\n”之外的任何單個字符。若要匹配包括”\r\n”在內的任意字符,請使用諸如”[\s\S]”之類的模式。
‘x|y’ 匹配 x 或 y。例如,’z
[xyz] 字符集。匹配包含的任一字符。例如,”[abc]”匹配”plain”中的”a”。
[^xyz] 反向字符集。匹配未包含的任何字符。例如,”[^abc]”匹配”plain”中”p”,”l”,”i”,”n”。
[a-z] 字符範圍。匹配指定範圍內的任何字符。例如,”[a-z]”匹配”a”到”z”範圍內的任何小寫字母。
[^a-z] 反向範圍字符。匹配不在指定的範圍內的任何字符。例如,”[^a-z]”匹配任何不在”a”到”z”範圍內的任何字符。
\b 匹配一個字邊界,即字與空格間的位置。例如,”er\b”匹配”never”中的”er”,但不匹配”verb”中的”er”。
\B 非字邊界匹配。”er\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。
\cx 匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回車符。x 的值必須在 A-Z 或 a-z 之間。如果不是這樣,則假定 c 就是”c”字符本身。
\d 數字字符匹配。等效於 [0-9]。
\D 非數字字符匹配。等效於 [^0-9]。
\f 換頁符匹配。等效於 \x0c 和 \cL。
\n 換行符匹配。等效於 \x0a 和 \cJ。
\r 匹配一個回車符。等效於 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、製表符、換頁符等。與 [ \f\n\r\t\v] 等效。
\S 匹配任何非空白字符。與 [^ \f\n\r\t\v] 等效。
\t 製表符匹配。與 \x09 和 \cI 等效。
\v 垂直製表符匹配。與 \x0b 和 \cK 等效。
\w 匹配任何字類字符,包括下劃線。與”[A-Za-z0-9_]”等效。
\W 與任何非單詞字符匹配。與”[^A-Za-z0-9_]”等效。
\xn 匹配 n,此處的 n 是一個十六進制轉義碼。十六進制轉義碼必須正好是兩位數長。例如,”\x41”匹配”A”。”\x041”與”\x04”&”1”等效。允許在正則表達式中使用 ASCII 代碼。
\num 匹配 num,此處的 num 是一個正整數。到捕獲匹配的反向引用。例如,”(.)\1”匹配兩個連續的相同字符。
\n 標識一個八進制轉義碼或反向引用。如果 \n 前面至少有 n 個捕獲子表達式,那麼 n 是反向引用。否則,如果 n 是八進制數 (0-7),那麼 n 是八進制轉義碼。
\nm 標識一個八進制轉義碼或反向引用。如果 \nm 前面至少有 nm 個捕獲子表達式,那麼 nm 是反向引用。如果 \nm 前面至少有 n 個捕獲,則 n 是反向引用,後面跟有字符 m。如果兩種前面的情況都不存在,則 \nm 匹配八進制值 nm,其中 n 和 m 是八進制數字 (0-7)。
\nml 當 n 是八進制數 (0-3),m 和 l 是八進制數 (0-7) 時,匹配八進制轉義碼 nml。
\un 匹配 n,其中 n 是以四位十六進制數表示的 Unicode 字符。例如,\u00A9 匹配版權符號 (©)。

反斜線、轉義和引用
反斜線字符 (‘\’) 用於引用轉義構造,如上表所定義的,同時還用於引用其他將被解釋爲非轉義構造的字符。因此,表達式 \ 與單個反斜線匹配,而 { 與左括號匹配。
在不表示轉義構造的任何字母字符前使用反斜線都是錯誤的;它們是爲將來擴展正則表達式語言保留的。可以在非字母字符前使用反斜線,不管該字符是否非轉義構造的一部分。
根據 Java Language Specification 的要求,Java 源代碼的字符串中的反斜線被解釋爲 Unicode 轉義或其他字符轉義。因此必須在字符串字面值中使用兩個反斜線,表示正則表達式受到保護,不被 Java 字節碼編譯器解釋。例如,當解釋爲正則表達式時,字符串字面值 “\b” 與單個退格字符匹配,而 “\b” 與單詞邊界匹配。字符串字面值 “(hello)” 是非法的,將導致編譯時錯誤;要與字符串 (hello) 匹配,必須使用字符串字面值 “\(hello\)”。
字符類
字符類可以出現在其他字符類中,並且可以包含並集運算符(隱式)和交集運算符 (&&)。並集運算符表示至少包含其某個操作數類中所有字符的類。交集運算符表示包含同時位於其兩個操作數類中所有字符的類。
字符類運算符的優先級如下所示,按從最高到最低的順序排列:
1 2 3 4 5
字面值轉義 \x
分組 […]
範圍 a-z
並集 [a-e][i-u]
交集 [a-z&&[aeiou]]
注意,元字符的不同集合實際上位於字符類的內部,而非字符類的外部。例如,正則表達式 . 在字符類內部就失去了其特殊意義,而表達式 - 變成了形成元字符的範圍。
行結束符
行結束符 是一個或兩個字符的序列,標記輸入字符序列的行結尾。以下代碼被識別爲行結束符:
新行(換行)符 (‘\n’)、
後面緊跟新行符的回車符 (“\r\n”)、
單獨的回車符 (‘\r’)、
下一行字符 (‘\u0085’)、
行分隔符 (‘\u2028’) 或
段落分隔符 (‘\u2029)。
如果激活 UNIX_LINES 模式,則新行符是唯一識別的行結束符。
如果未指定 DOTALL 標誌,則正則表達式 . 可以與任何字符(行結束符除外)匹配。
默認情況下,正則表達式 ^ 和 MULTILINEMULTILINE 僅在行結束符之前或輸入序列的結尾處匹配。
組和捕獲
捕獲組可以通過從左到右計算其開括號來編號。例如,在表達式 ((A)(B(C))) 中,存在四個這樣的組:
1 2 3 4
((A)(B(C)))
\A
(B(C))
(C)
組零始終代表整個表達式。
之所以這樣命名捕獲組是因爲在匹配中,保存了與這些組匹配的輸入序列的每個子序列。捕獲的子序列稍後可以通過 Back 引用在表達式中使用,也可以在匹配操作完成後從匹配器獲取。
與組關聯的捕獲輸入始終是與組最近匹配的子序列。如果由於量化的緣故再次計算了組,則在第二次計算失敗時將保留其以前捕獲的值(如果有的話)例如,將字符串 “aba” 與表達式 (a(b)?)+ 相匹配,會將第二組設置爲 “b”。在每個匹配的開頭,所有捕獲的輸入都會被丟棄。
以 (?) 開頭的組是純的非捕獲 組,它不捕獲文本,也不針對組合計進行計數。
Unicode 支持
此類符合 Unicode Technical Standard #18:Unicode Regular Expression Guidelines 第 1 級和 RL2.1 Canonical Equivalents。
Java 源代碼中的 Unicode 轉義序列(如 \u2014)是按照 Java Language Specification 的 第 3.3 節中的描述處理的。這樣的轉義序列還可以由正則表達式解析器直接實現,以便在從文件或鍵盤擊鍵讀取的表達式中使用 Unicode 轉義。因此,可以將不相等的字符串 “\u2014” 和 “\u2014” 編譯爲相同的模式,從而與帶有十六進制值 0x2014 的字符匹配。
與 Perl 中一樣,Unicode 塊和類別是使用 \p 和 \P 構造編寫的。如果輸入具有屬性 prop,則與 \p{prop} 匹配,而輸入具有該屬性時與 \P{prop} 不匹配。塊使用前綴 In 指定,與在 InMongolian 中一樣。可以使用可選前綴 Is 指定類別:\p{L} 和 \p{IsL} 都表示 Unicode 字母的類別。塊和類別在字符類的內部和外部都可以使用。
受支持的類別是由 Character 類指定版本中的 The Unicode Standard 的類別。類別名稱是在 Standard 中定義的,即標準又豐富。Pattern 所支持的塊名稱是 UnicodeBlock.forName 所接受和定義的有效塊名稱。
行爲類似 java.lang.Character boolean 是 methodname 方法(廢棄的類別除外)的類別,可以通過相同的 \p{prop} 語法來提供,其中指定的屬性具有名稱 javamethodname。
與 Perl 5 相比較
Pattern 引擎用有序替換項執行傳統上基於 NFA 的匹配,與 Perl 5 中進行的相同。
此類不支持 Perl 構造:
條件構造 (?{X}) 和 (?(condition)X|Y)、
嵌入式代碼構造 (?{code}) 和 (??{code})、
嵌入式註釋語法 (?#comment) 和
預處理操作 \l \u、\L 和 \U。
此類支持但 Perl 不支持的構造:
Possessive 數量詞,它可以儘可能多地進行匹配,即使這樣做導致所有匹配都成功時也如此。
字符類並集和交集,如上文所述。
與 Perl 的顯著不同點是:
在 Perl 中,\1 到 \9 始終被解釋爲 Back 引用;如果至少存在多個子表達式,則大於 9 的反斜線轉義數按 Back 引用對待,否則在可能的情況下,它將被解釋爲八進制轉義。在此類中,八進制轉義必須始終以零開頭。在此類中,\1 到 \9 始終被解釋爲 Back 引用,較大的數被接受爲 Back 引用,如果在正則表達式中至少存在多個子表達式的話;否則,解析器將刪除數字,直到該數小於等於組的現有數或者其爲一個數字。
Perl 使用 g 標誌請求恢復最後匹配丟失的匹配。此功能是由 Matcher 類顯式提供的:重複執行 find 方法調用可以恢復丟失的最後匹配,除非匹配器被重置。
在 Perl 中,位於表達式頂級的嵌入式標記對整個表達式都有影響。在此類中,嵌入式標誌始終在它們出現的時候才起作用,不管它們位於頂級還是組中;在後一種情況下,與在 Perl 中類似,標誌在組的結尾處還原。
Perl 允許錯誤匹配構造,如在表達式 a 中,以及不匹配的括號,如在在表達式 abc] 中,並將其作爲字面值對待。此類還接受不匹配的括號,但對 +、? 和 不匹配元字符有嚴格限制;如果遇到它們,則拋出 PatternSyntaxException。
有關正則表達式構造行爲更準確的描述,請參見 Mastering Regular Expressions, 2nd Edition,該書由 Jeffrey E. F. Friedl、O’Reilly 和 Associates 合著,於 2002 年出版。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章