正則表達式是一種強大而靈活的文本處理工具。使用正則表達式,我們能夠以編程的方式,構造復雜的文本模式,並對輸入的字符串進行搜索。
一旦找到了匹配這些模式的部分,你就能夠隨心所欲地對它們進行處理。
0.0:為什么用正則表達式?
正則表達式定義了字符串的模式。
正則表達式可以用來搜索、編輯或處理文本。
1:基礎知識
一般而言,正則表達式就是以某種方式來描述字符串。
例如,要找一個數字,它可能有一個負號在最前面,那你就寫一個負號加上一個問號,就像這樣: - ?
1.1:正則表達式中反斜杠的作用:
在其他語言中,\\表示“我想要在正則表達式中插入一個普通的(字面上的)反斜線,請不要給它任何特殊的意義。
”而在Java中,\\ 的意思是“我要插入一個正則表達武的反斜線,所以其后的字符具有特殊的意義。”
(1) 例如,如果你想表示一位數字,那么正則表達式應該是\\d。如果你想插入一個普通的反斜線,則應該這樣\\\\。
(2) 要表示 “一個或多個之前的表達式“,應該使用 + , 所以,如果要表示“可能有一個負號,后面跟着一位或多位數字”,可以這樣:-? \\ d+
(3)正則表達式中,括號有着將表達式分組的效果,而豎直線 | 則表示或操作。
(-|\\+)?
這個正則表達式表示字符串的起始字符可能是一個 -或 +,或二者皆沒有(因為后面跟着?修飾符)。
因為字符 + 在正則表達式中有特殊的意義,所以必須使用\\ 其轉義,使之成為表達式中的一個普通字符。
2:正則表達式語法
字符 |
說明 |
---|---|
\ |
將下一字符標記為特殊字符、文本、反向引用或八進制轉義符。例如,"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]"之類的模式。 |
(pattern) |
匹配 pattern 並捕獲該匹配的子表達式。可以使用 $0…$9 屬性從結果"匹配"集合中檢索捕獲的匹配。若要匹配括號字符 ( ),請使用"\("或者"\)"。 |
(?:pattern) |
匹配 pattern 但不捕獲該匹配的子表達式,即它是一個非捕獲匹配,不存儲供以后使用的匹配。這對於用"or"字符 (|) 組合模式部件的情況很有用。例如,'industr(?:y|ies) 是比 'industry|industries' 更經濟的表達式。 |
(?=pattern) |
執行正向預測先行搜索的子表達式,該表達式匹配處於匹配 pattern 的字符串的起始點的字符串。它是一個非捕獲匹配,即不能捕獲供以后使用的匹配。例如,'Windows (?=95|98|NT|2000)' 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。預測先行不占用字符,即發生匹配后,下一匹配的搜索緊隨上一匹配之后, 而不是在組成預測先行的字符后。 |
(?!pattern) |
執行反向預測先行搜索的子表達式,該表達式匹配不處於匹配 pattern 的字符串的起始點的搜索字符串。它是一個非捕獲匹配,即不能捕獲供以后使用的匹配。例如,'Windows (?!95|98|NT|2000)' 匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。預測先行不占用字符,即發生匹配后,下一匹配的搜索緊隨上一匹配之后,而不是在組成預測先行的字符后。 |
x|y |
匹配 x 或 y。例如,'z|food' 匹配"z"或"food"。'(z|f)ood' 匹配"zood"或"food"。 |
[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 匹配版權符號 (©)。 |
正則表達式完整構造子列
字符類
我們利用正則表達式的目地:用最簡單的正則表達式來表示復雜的代碼或者復雜的任務。
量詞: Greedy(貪婪), Reluctant(懶惰), Possessive(強占)三種,一下分別介紹;
Greedy 數量詞:為java中最常用的量詞。
X? X,一次或一次也沒有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超過 m 次
2:在java API中包含有三個類
實例1:
1 package com.hone.regex; 2 3 import java.util.regex.Pattern; 4 5 public class RegexExample1 { 6 public static void main(String args[]){ 7 String content = "I am noob from runoob.com."; 8 //定義一個正則表達式 9 String pattern = ".*runoob.*"; 10 //有兩種類型的matches()方法 11 //方法1:matches(String regex, CharSequence input) 12 boolean isMatch = Pattern.matches(pattern, content); 13 System.out.println("字符串中是否包含了 'runoob' 子字符串 ? " + isMatch); 14 } 15 }
實例2:
package com.hone.regex; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexMatches2 { public static void main( String args[] ){ // 按指定模式在字符串查找 String line = "This order was placed for QT3000! OK?"; String pattern = "(\\D*)(\\d+)(.*)";// \d 數字字符匹配。等效於 [0-9]。\D非數字字符匹配。等效於 [^0-9]。 // 創建 Pattern 對象 Pattern r = Pattern.compile(pattern); // 現在創建 matcher 對象 //利用matcher()的第二個方法:matcher(CharSequence input) Matcher m = r.matcher(line); if (m.find( )) { System.out.println("Found value: " + m.group(0) ); System.out.println("Found value: " + m.group(1) ); System.out.println("Found value: " + m.group(2) ); System.out.println("Found value: " + m.group(3) ); } else { System.out.println("NO MATCH"); } } }
結果輸出:
Found value: This order was placed for QT3000! OK? Found value: This order was placed for QT Found value: 3000 Found value: ! OK?
Matcher 類的方法
索引方法
索引方法提供了有用的索引值,精確表明輸入字符串中在哪能找到匹配:
檢查輸入字符串
均返回一個boolean值
實例:
1 package com.hone.regex; 2 3 import java.util.regex.Matcher; 4 import java.util.regex.Pattern; 5 6 /* 7 * matcher 要求整個序列都匹配, 8 * lookingAt 則只需要部分匹配成功就可以,但是需要從第一個字符開始匹配 9 */ 10 public class RegexMatches6lookingAt { 11 private static final String REGEX = "foo"; 12 private static final String INPUT = "fooooooooooooooooo"; 13 private static final String INPUT2 = "ooooofoooooooooooo"; 14 private static Pattern pattern; 15 private static Matcher matcher; 16 private static Matcher matcher2; 17 18 public static void main( String args[] ){ 19 pattern = Pattern.compile(REGEX); 20 matcher = pattern.matcher(INPUT); 21 matcher2 = pattern.matcher(INPUT2); 22 23 System.out.println("Current REGEX is: "+REGEX); 24 System.out.println("Current INPUT is: "+INPUT); 25 System.out.println("Current INPUT2 is: "+INPUT2); 26 27 28 System.out.println("lookingAt(): "+matcher.lookingAt());//true 29 System.out.println("matches(): "+matcher.matches());//false 30 System.out.println("lookingAt(): "+matcher2.lookingAt());//false 31 } 32 33 }
替換方法
package com.hone.regex; import java.util.regex.Matcher; import java.util.regex.Pattern; /* * replaceFirst 和 replaceAll 方法用來替換匹配正則表達式的文本。 * 不同的是,replaceFirst 替換首次匹配,replaceAll 替換所有匹配。 */ public class RegexMatches7replace { private static String REGEX = "dog"; private static String INPUT = "The dog says meow. All dogs say meow."; private static String REPLACE = "cat"; public static void main(String[] args) { Pattern p = Pattern.compile(REGEX); // get a matcher object Matcher m = p.matcher(INPUT); INPUT = m.replaceFirst(REPLACE); //INPUT = m.replaceAll(REPLACE); System.out.println(INPUT); } }
實例2:
package com.hone.regex; import java.util.regex.Matcher; import java.util.regex.Pattern; /* * appendReplacement()方法實現非終端替換 * 在末端替換 */ public class RegexMatches8appendReplacement { //* 表示零次或多次匹配前面的字符或子表達式 private static String REGEX = "a*b"; private static String INPUT = "aabfooaabfooabfoob"; private static String REPLACE = "-"; public static void main(String[] args) { Pattern p = Pattern.compile(REGEX); // 獲取 matcher 對象 Matcher m = p.matcher(INPUT); StringBuffer sb = new StringBuffer(); while(m.find()){ m.appendReplacement(sb,REPLACE); } m.appendTail(sb); System.out.println(sb.toString()); } }
輸出結果:
-foo-foo-foo-
PatternSyntaxException 類的方法
PatternSyntaxException 是一個非強制異常類,它指示一個正則表達式模式中的語法錯誤。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
python 的re模塊
(此篇文章只是收錄別人的,原博客地址:http://www.cnblogs.com/PythonHome/archive/2011/11/19/2255459.html)
原則上python的正則表達式與java的語法基本類似。
這個模塊提供了與 Perl 相似l的正則表達式匹配操作。Unicode字符串也同樣適用。
正則表達式使用反斜杠" \ "來代表特殊形式或用作轉義字符,這里跟Python的語法沖突,因此,Python用" \\\\ "表示正則表達式中的" \ ",因為正則表達式中如果要匹配" \ ",需要用\來轉義,變成" \\ ",而Python語法中又需要對字符串中每一個\進行轉義,所以就變成了" \\\\ "。
上面的寫法是不是覺得很麻煩,為了使正則表達式具有更好的可讀性,Python特別設計了原始字符串(raw string),需要提醒你的是,在寫文件路徑的時候就不要使用raw string了,這里存在陷阱。raw string就是用'r'作為字符串的前綴,如 r"\n":表示兩個字符"\"和"n",而不是換行符了。Python中寫正則表達式時推薦使用這種形式。
絕大多數正則表達式操作與 模塊級函數或RegexObject方法 一樣都能達到同樣的目的。而且不需要你一開始就編譯正則表達式對象,但是不能使用一些實用的微調參數。
1.正則表達式語法
為了節省篇幅,這里不再敘述了。
2.martch和search的區別
Python提供了兩種不同的原始操作:match和search。match是從字符串的起點開始做匹配,而search(perl默認)是從字符串做任意匹配。
注意:當正則表達式是' ^ '開頭時,match與search是相同的。match只有當且僅當被匹配的字符串開頭就能匹配 或 從pos參數的位置開始就能匹配 時才會成功。如下:
>>> import re
>>> re.match("c", "abcdef")
>>> re.search("c","abcdef")
<_sre.SRE_Match object at 0x00A9A988>
>>> re.match("c", "cabcdef")
<_sre.SRE_Match object at 0x00A9AB80>
>>> re.search("c","cabcdef")
<_sre.SRE_Match object at 0x00AF1720>
>>> patterm = re.compile("c")
>>> patterm.match("abcdef")
>>> patterm.match("abcdef",1)
>>> patterm.match("abcdef",2)
<_sre.SRE_Match object at 0x00A9AB80>
3.模塊內容
re.compile(pattern, flags=0)
編譯正則表達式,返回RegexObject對象,然后可以通過RegexObject對象調用match()和search()方法。
prog = re.compile(pattern)
result = prog.match(string)
跟
result = re.match(pattern, string)
是等價的。
第一種方式能實現正則表達式的重用。
re.search(pattern, string, flags=0)
在字符串中查找,是否能匹配正則表達式。返回_sre.SRE_Match對象,如果不能匹配返回None。
re.match(pattern, string, flags=0)
字符串的開頭是否能匹配正則表達式。返回_sre.SRE_Match對象,如果不能匹配返回None。
re.split(pattern, string, maxsplit=0)
通過正則表達式將字符串分離。如果用括號將正則表達式括起來,那么匹配的字符串也會被列入到list中返回。maxsplit是分離的次數,maxsplit=1分離一次,默認為0,不限制次數。
>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
注意:我使用的Python是2.6,查看源代碼發現split()並沒有flags的參數,2.7才增加。這種問題我發現不止一次了,官方的文檔 跟 源碼不一致的現象,如果發現異常,應該去源碼中找找原因。
如果在字符串的開始或結尾就匹配,返回的list將會以空串開始或結尾。
>>> re.split('(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']
如果字符串不能匹配,將會返回整個字符串的list。
>>> re.split("a","bbb")
['bbb']
re.findall(pattern, string, flags=0)
找到 RE 匹配的所有子串,並把它們作為一個列表返回。這個匹配是從左到右有序地返回。如果無匹配,返回空列表。
>>> re.findall("a","bcdef")
[]
>>> re.findall(r"\d+","12a32bc43jf3")
['12', '32', '43', '3']
re.finditer(pattern, string, flags=0)
找到 RE 匹配的所有子串,並把它們作為一個迭代器返回。這個匹配是從左到右有序地返回。如果無匹配,返回空列表。
>>> it = re.finditer(r"\d+","12a32bc43jf3")
>>> for match in it:
print match.group()
12
32
43
3
re.sub(pattern, repl, string, count=0, flags=0)
找到 RE 匹配的所有子串,並將其用一個不同的字符串替換。可選參數 count 是模式匹配後替換的最大次數;count 必須是非負整數。缺省值是 0 表示替換所有的匹配。如果無匹配,字符串將會無改變地返回。
re.subn(pattern, repl, string, count=0, flags=0)
與re.sub方法作用一樣,但返回的是包含新字符串和替換執行次數的兩元組。
re.escape(string)
對字符串中的非字母數字進行轉義
re.purge()
清空緩存中的正則表達式
4.正則表達式對象
re.RegexObject
re.compile()返回RegexObject對象
re.MatchObject
group()返回被 RE 匹配的字符串
start()返回匹配開始的位置
end()返回匹配結束的位置
span()返回一個元組包含匹配 (開始,結束) 的位置
5.編譯標志
編譯標志讓你可以修改正則表達式的一些運行方式。在 re 模塊中標志可以使用兩個名字,一個是全名如 IGNORECASE,一個是縮寫,一字母形式如 I。(如果你熟悉 Perl 的模式修改,一字母形式使用同樣的字母;例如 re.VERBOSE的縮寫形式是 re.X。)多個標志可以通過按位 OR-ing 它們來指定。如 re.I | re.M 被設置成 I 和 M 標志:
I
IGNORECASE
使匹配對大小寫不敏感;字符類和字符串匹配字母時忽略大小寫。舉個例子,[A-Z]也可以匹配小寫字母,Spam 可以匹配 "Spam", "spam", 或 "spAM"。這個小寫字母並不考慮當前位置。
L
LOCALE
影響 "w, "W, "b, 和 "B,這取決於當前的本地化設置。
locales 是 C 語言庫中的一項功能,是用來為需要考慮不同語言的編程提供幫助的。舉個例子,如果你正在處理法文文本,你想用 "w+ 來匹配文字,但 "w 只匹配字符類 [A-Za-z];它並不能匹配 "é" 或 "?"。如果你的系統配置適當且本地化設置為法語,那么內部的 C 函數將告訴程序 "é" 也應該被認為是一個字母。當在編譯正則表達式時使用 LOCALE 標志會得到用這些 C 函數來處理 "w 後的編譯對象;這會更慢,但也會象你希望的那樣可以用 "w+ 來匹配法文文本。
M
MULTILINE
(此時 ^ 和 $ 不會被解釋; 它們將在 4.1 節被介紹.)
使用 "^" 只匹配字符串的開始,而 $ 則只匹配字符串的結尾和直接在換行前(如果有的話)的字符串結尾。當本標志指定後, "^" 匹配字符串的開始和字符串中每行的開始。同樣的, $ 元字符匹配字符串結尾和字符串中每行的結尾(直接在每個換行之前)。
S
DOTALL
使 "." 特殊字符完全匹配任何字符,包括換行;沒有這個標志, "." 匹配除了換行外的任何字符。
X
VERBOSE
該標志通過給予你更靈活的格式以便你將正則表達式寫得更易於理解。當該標志被指定時,在 RE 字符串中的空白符被忽略,除非該空白符在字符類中或在反斜杠之後;這可以讓你更清晰地組織和縮進 RE。它也可以允許你將注釋寫入 RE,這些注釋會被引擎忽略;注釋用 "#"號 來標識,不過該符號不能在字符串或反斜杠之後。
最后:如果能用字符串的方法,就不要選擇正則表達式,因為字符串方法更簡單快速。