什么是正則表達式?
正則表達式(Regular?Expression)就是用某種模式去匹配一類字符串的公式。如你要在一篇文章中查找第一個字是“李”最后一個字是“建”的三個字的姓名,即“李*建”;那么“李*建”就是公式,也稱作模式(Pattern),這篇文章就是要匹配的串(或叫文本text)。再如,你要檢查輸入的一個字符串是否是126郵箱的格式,你得制定一個規則去查檢,這種規則就是正則表達式。
從入門開始
我們就從上面提到的一個例子開始:檢查一個字符串是否符合126郵箱的格式。
我們從網易的郵箱注冊頁面可以看到126郵箱的用戶名需要符合以下的格式:6~18個字符,可使用字母、數字、下劃線,需以字母開頭。我們可以定義一個模式:^[a-zA-Z]\w{5,17}@126.com
這個模式可以這樣理解:
[a-zA-Z]:任何一個a到z或A到Z的英文字母
^: ? ? ?表示以什么開頭,則^[a-zA-Z]表示以字母開頭
\w: ? ? 單詞字符[a-zA-Z_0-9],即a-z或A-Z或0-9或_中的任何一個字符
{5,17}: ?表示出現5到17次(至少5次,不超過17次),則\w{5,17}表示5~17個字符。
? ? ? ? ? ? ? ? 因為還有一個以非數字字母開頭的字符,所以^[a-zA-Z]\w{5,17}表示:“6~18個字符,可使用字母、數字、下劃線,需以字母開頭”
@126.com:表示符合以上規則的用戶名后跟上@126.com字符串,即組成一個郵箱地址。
^[a-zA-Z]\w{5,17}@126.com”就是我們所說的正則表達式,用Java的簡單實現如下:
- String?regex?=?"^[a-zA-Z]\\w{5,17}@126\\.com";??//定義匹配的規則:正則表達式??
- //說明:126.com中的.需要轉義\\.??
- String?text?=?"ZhanSan@126fcom";????//要檢查的字符串??
- boolean?isMatched?=?text.matches(regex);????//判斷text是否符合規則regex??
- System.out.println(isMatched);??
正則表達式常用符號
上面一個示例中用到的“^”、“\w”、“{5,17}”等都是正則表達式中的常用符號,這些符號在正則表達式中都有特殊的含意。下面這個表格是Java中的正則表達式常用符號的含意(只抽取了其常用的部分進行說明,就這些部分其實可以解決關于正則表達式的絕大多數的問題了)。
模式 | 匹配的內容(含意) |
? | ? |
字符類 | |
[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?次 |
? | ? |
邏輯運算符 | |
XY | X?后跟?Y |
X|Y | X?或?Y |
(X) | X,作為捕獲組 |
參考文檔:Class?Pattern
?
這些常用的符號在各種編程語言的正則表達式中含意基本相同(因為正則表達式的思想是相同的),所以都可以用來參數。但不同的語言可能會有一些細小的差別,如果要針對各種編程語言,想有更精確和權威的說明,可參考其官方文檔:
C++(VS2013編譯器):http://msdn.microsoft.com/zh-cn/library/bb982727.aspx#grammarsummary
Java:??????????????http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
JavaScript:?????????http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp
?
?
正則表達式的使用
下面從常見的需求出發講述C++、Java和JavaScript中正則表達式的使用
C++中的正則表達式
C++中正則表達式主要有三種實現方式:C語言的實現方式(C?regex),C++標準庫的實現(C++?regex),Boost庫的實現(boost?regex)。C?regex的方式是一種面向過程的編程方式,使用起來不太方便;C++?regex的方式因為是標準庫的一部分,所以可以直接使用(好像Linux平臺下不支持),但C++?regex非常難用,語法要求比較嚴格,而且好多默認的選項和我們正常的想法不一樣;Boost是一個開源的第三方庫,這個庫非常優秀,廣泛應用于C++的項目開發中,boost?regex非常靈活好用,C++開發時是大家推崇的一種方式。
關于boost?regex的用法,在后繼的文章將會進一步介紹,現在以C++?regex的方式列舉一個使用樣例。
1.驗證ip地址
- #include?<regex>??
- #include?<iostream>??
- #include?<string>??
- ??
- bool?IsIpV4Address(const?std::string&?strIp)??
- {??
- ????//驗證IP地址的模式,這里"\."中的"\"是轉義字符,表示這是一個.??
- ????const?std::regex?pattern("(\\d{1,3}){1}\.(\\d{1,3}){1}\.(\\d{1,3}){1}\.(\\d{1,3}){1}");??
- ????//匹配驗證??
- ????return?std::regex_match(strIp,?pattern);??
- }??
- ??
- int?main()??
- {??
- ????std::string?strIp1?=?"134.34.34.4";//192.168.1.1??
- ????std::string?strIp2?=?"192.168.255";??
- ??
- ????std::cout?<<?strIp1?<<?"?:?"?<<?(IsIpV4Address(strIp1)???"valid"?:?"invalid")?<<?std::endl;??
- ????std::cout?<<?strIp2?<<?"?:?"?<<?(IsIpV4Address(strIp2)???"valid"?:?"invalid")?<<?std::endl;??
- ????return?0;??
- }??
?
Java中的正則表達式
1.驗證一個字符串是否為URL
- public?static?boolean?isUrl(String?text)?{??
- ????String?regex?=?"^http://([\\w-]+.)+[\\w-]+(/[\\w-./?%&=#]*)?$";??
- ????return?text.matches(regex);??
- }??
2.判斷一個文本中有多少個URL,并將所有的URL加上超鏈接.
如以下文本:
C++(VS2013編譯器):http://msdn.microsoft.com/zh-cn/library/bb982727.aspx#grammarsummary
Java:??????????????http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
JavaScript:?????????http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp
添加鏈接后變成:
C++(VS2013編譯器):<a?href=”http://msdn.microsoft.com/zh-cn/library/bb982727.aspx#grammarsummary
”>http://msdn.microsoft.com/zh-cn/library/bb982727.aspx#grammarsummary</a>
Java:??????????????<a?href=”http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
”>http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html</a>
JavaScript:?????????<a?href=”http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp
”>http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp</a>
?
- /**?
- ?*?給一個字符串添加鏈接?
- ?*?@param?text?要添加鏈接的字符串?
- ?*?@param?url?鏈接的URL?
- ?*?@return?添加鏈接后的字符串?
- ?*/??
- public?static?String?AddHref(String?text,?String?url)?{??
- ????return??"<a?href=\""?+?url?+??"\">"?+?text?+?"</a>";??
- }??
- ??
- /**?
- ?*?查找文本中的URL字符串,并將其添加鏈接?
- ?*?@param?text?需要查找的文本?
- ?*?@return?添加鏈接后的文本?
- ?*/??
- public?static?String?AddLinkToText(String?text)?{??
- ????Pattern?pattern?=?Pattern.compile("http://([\\w-]+.)+[\\w-]+(/[\\w-./?%&=#]*)?");??
- ????Matcher?matcher?=?pattern.matcher(text);??
- ????StringBuffer?sb?=?new?StringBuffer();???????????//定義一個字符緩沖區,用于保存新的文本??
- ????while?(matcher.find())?{??
- ????????String?matchedSubStr?=?matcher.group();?????//提取出查找到的子串??
- ????????matcher.appendReplacement(sb,?AddHref(matchedSubStr,?matchedSubStr));???//將找到的子串添加鏈接后塞到字符緩沖區內??
- ????}??
- ????matcher.appendTail(sb);??
- ????return?sb.toString();??
- }?????
?
JavaScript中的正則表達式
JavaScript中的正則表達式是通過RegExp對象實現的。RegExp對象的創建有三種方式:
精簡方式:
/pattern/attributes
new方式:
new?RegExp(pattern,?attributes);
函數調用的方式:
RegExp(pattern,?attributes);
?
????參數pattern可以是一個模式串,也可以是一個RegExp對象,如果pattern本身就是RegExp的對象,則attributes參數將不起作用(新創建的對象的必發與pattern對象相同。),需要省略,如果不省略會拋TypeError?異常。
????參數attributes有三種屬性"g"、"i"?和?"m",分別用于指定全局匹配、區分大小寫的匹配和多行匹配。
?
RegExp主要有三個方法:
compile | 編譯正則表達式,可用于改變和重新編譯正則表達式。 |
exec | 檢索字符串中指定的值。返回找到的值,并確定其位置。 |
test | 檢索字符串中是否有指定的值。返回?true?或?false。 |
?
?
1.驗證字符串是否為數字
- <script?type="text/javascript">??
- ????function?isNumber(text)?{??
- ????????var?pattern?=?new?RegExp("^\\d*$");??
- ????????return?pattern.test(text);??
- ????}??
- ???????
- ????var?value1?=?"1234";??
- ????document.write(value1?+?"?is?Numed:"?+?isNumber(value1));??
- </script>??
2.郵箱格式:
- <script?type="text/javascript">??
- ????function?isEmail(text)?{??
- ????????var?reg?=?/^([\w-.])+@([\w-])+((\.[\w-]{2,3}){1,2})$/;??
- ????????return?reg.test(text);??
- ????}??
- ???
- ????var?value2?=?"Zhang.San@163.com";??
- ????document.write(value2?+?"?is?Email:"?+?isEmail(value2));??
- </script>??
?
3.將一個文本中的所有郵箱地址和在文本中的位置打印到頁面
- <script?type="text/javascript">??
- ????function?PrintEmail(text)?{??
- ????//匹配的模式??
- ????var?reg?=?RegExp("([\\w-.])+@([\\w-])+((\.[\\w-]{2,3}){1,2})",?"g");??
- ????var?result;?//保存結果??
- ???
- ????while?((result?=?reg.exec(text))?!=?null)??{??
- ????????document.write(result[0]?+?"<br/>"?+?result.index);??
- ????????document.write("<br/><br/>");??
- ????}??
- ????}??
- ???
- ????var?text?=?"張三?Zhang.San@163.com;?李四?Li_si@126.com;王五?WangWu@gmail.com.cn"?;??
- ????PrintEmail(text);??
- </script>??
應用場景
數據驗證:
例如,可以檢查輸入的字符串,看其是否為電話號碼格式,或是否為郵箱格式。?這在網頁的表單輸入中經常用到。
查找子串:
可以查找文檔內(或一個字符串內)符合指定模式的子串。
替換文本:
可以使用正則表達式來識別文檔中的特定內容,完全刪除該部分內容或者用其他字符串來替換它。
使用工具:
如Word、NotePad++、EditPlus等文字編輯器中的查找功能都支持正則表達式,用正則表達式你就可以實現更加多樣化的查找。還有像VS、CodeBlock、Eclipse、Intellij?Idea等開發工具的IDE的查找替換功能也都支持正則表達式,用它你可以修改變量名,調整代碼格式,統計代碼行數等。
?
?
常用正則表達式總結
常用的正則表達式已經有很多人做了總結了,在網上能夠找到非常多,我就沒有再寫的必要了。下面貼出我覺得還不錯的一個總結。
此部分內容為轉載,來自:http://www.cnblogs.com/zxin/archive/2013/01/26/2877765.html
?
一、校驗數字的表達式
1 數字:^[0-9]*$ 2 n位的數字:^\d{n}$ 3 至少n位的數字:^\d{n,}$ 4 m-n位的數字:^\d{m,n}$ 5 零和非零開頭的數字:^(0|[1-9][0-9]*)$ 6 非零開頭的最多帶兩位小數的數字:^([1-9][0-9]*)+(.[0-9]{1,2})?$ 7 帶1-2位小數的正數或負數:^(\-)?\d+(\.\d{1,2})?$ 8 正數、負數、和小數:^(\-|\+)?\d+(\.\d+)?$ 9 有兩位小數的正實數:^[0-9]+(.[0-9]{2})?$ 10 有1~3位小數的正實數:^[0-9]+(.[0-9]{1,3})?$ 11 非零的正整數:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$ 12 非零的負整數:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$ 13 非負整數:^\d+$ 或 ^[1-9]\d*|0$ 14 非正整數:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$ 15 非負浮點數:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ 16 非正浮點數:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ 17 正浮點數:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ 18 負浮點數:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ 19 浮點數:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
二、校驗字符的表達式
1 漢字:^[\u4e00-\u9fa5]{0,}$ 2 英文和數字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$ 3 長度為3-20的所有字符:^.{3,20}$ 4 由26個英文字母組成的字符串:^[A-Za-z]+$ 5 由26個大寫英文字母組成的字符串:^[A-Z]+$ 6 由26個小寫英文字母組成的字符串:^[a-z]+$ 7 由數字和26個英文字母組成的字符串:^[A-Za-z0-9]+$ 8 由數字、26個英文字母或者下劃線組成的字符串:^\w+$ 或 ^\w{3,20}$ 9 中文、英文、數字包括下劃線:^[\u4E00-\u9FA5A-Za-z0-9_]+$ 10 中文、英文、數字但不包括下劃線等符號:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$ 11 可以輸入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+ 12 禁止輸入含有~的字符:[^~\x22]+
三、特殊需求表達式
1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ 2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.? 3 InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ 4 手機號碼:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$ 5 電話號碼("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 6 國內電話號碼(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7} 7 身份證號(15位、18位數字):^\d{15}|\d{18}$ 8 短身份證號碼(數字、字母x結尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$ 9 帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 10 密碼(以字母開頭,長度在6~18之間,只能包含字母、數字和下劃線):^[a-zA-Z]\w{5,17}$ 11 強密碼(必須包含大小寫字母和數字的組合,不能使用特殊字符,長度在8-10之間):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 12 日期格式:^\d{4}-\d{1,2}-\d{1,2} 13 一年的12個月(01~09和1~12):^(0?[1-9]|1[0-2])$ 14 一個月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$ 15 錢的輸入格式: 16 1.有四種錢的表示形式我們可以接受:"10000.00" 和 "10,000.00", 和沒有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$ 17 2.這表示任意一個不以0開頭的數字,但是,這也意味著一個字符"0"不通過,所以我們采用下面的形式:^(0|[1-9][0-9]*)$ 18 3.一個0或者一個不以0開頭的數字.我們還可以允許開頭有一個負號:^(0|-?[1-9][0-9]*)$ 19 4.這表示一個0或者一個可能為負的開頭不為0的數字.讓用戶以0開頭好了.把負號的也去掉,因為錢總不能是負的吧.下面我們要加的是說明可能的小數部分:^[0-9]+(.[0-9]+)?$ 20 5.必須說明的是,小數點后面至少應該有1位數,所以"10."是不通過的,但是 "10" 和 "10.2" 是通過的:^[0-9]+(.[0-9]{2})?$ 21 6.這樣我們規定小數點后面必須有兩位,如果你認為太苛刻了,可以這樣:^[0-9]+(.[0-9]{1,2})?$ 22 7.這樣就允許用戶只寫一位小數.下面我們該考慮數字中的逗號了,我們可以這樣:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ 23 8.1到3個數字,后面跟著任意個 逗號+3個數字,逗號成為可選,而不是必須:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ 24 備注:這就是最終結果了,別忘了"+"可以用"*"替代如果你覺得空字符串也可以接受的話(奇怪,為什么?)最后,別忘了在用函數時去掉去掉那個反斜杠,一般的錯誤都在這里 25 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$ 26 中文字符的正則表達式:[\u4e00-\u9fa5] 27 雙字節字符:[^\x00-\xff] (包括漢字在內,可以用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1))
28 空白行的正則表達式:\n\s*\r (可以用來刪除空白行) 29 HTML標記的正則表達式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (網上流傳的版本太糟糕,上面這個也僅僅能部分,對于復雜的嵌套標記依舊無能為力)
30 首尾空白字符的正則表達式:^\s*|\s*$或(^\s*)|(\s*$) (可以用來刪除行首行尾的空白字符(包括空格、制表符、換頁符等等),非常有用的表達式) 31 騰訊QQ號:[1-9][0-9]{4,} (騰訊QQ號從10000開始) 32 中國郵政編碼:[1-9]\d{5}(?!\d) (中國郵政編碼為6位數字) 33 IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址時有用)
34 IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))??? (由@飛龍三少 提供,感謝共享)
?
注意:
正則表達式是一個非常強大而又非常常用的一個編程技術,我以上這片文章也只是拋磚引玉,講述了其中最常用的一部分。因為其內容實在太龐大,如果要詳細描述,每一種編程語言的正則表達式都可以單獨成一本書。