在說具體的內容以前先來了解一下什麼是向前查找,向後查找與回溯。咱們經過一下小的例子來理解一下。具體的代碼附錄在最後。html
##向前查找 Java中向前查找的正則表達式是(?=),更加具體的就是 要匹配內容的正則(?=匹配的邊界的正則)。來一個具體的例子,好比咱們有一個具體的字符串2016年:雞翅 15元 雞腿 10元 雞爪 5元,如今咱們要取出裏面的價格15 10 5,而不要2016,顯然咱們不能直接\d+來匹配。 咱們很容易發現規律,咱們須要提取單位‘元’前面的數字,可是咱們不想要單位‘元’,怎麼辦,這裏就可使用向前查找了。java
content = "2016年:雞翅 15元 雞腿 10元 雞爪 5元"; //正則表示,匹配元前面的數字,以元做爲數字的後邊界可是不匹配‘元’ regex = "\\d+(?=元)";
匹配的結果就是15 10 5,不包含2016,後面有代碼能夠本身測試一下。正則表達式
##向後查找 首先向後查找的正則表達式是(?<=),更加具體的就是*(?<=匹配邊界的正則)要匹配內容的正則*,向後查找和向前查找同樣,只不過是匹配邊界後面的內容。下面仍是經過一個具體的例子來講明。好比我有一個url字符串:http://www.freemethod.cn,我想提取出www.freemethod.cn。要真麼作了。這裏就可使用向後匹配。固然你說我有一萬種方法能夠完成這個事情,在這個例子中的確有不少方法能夠完成這個工做,這裏爲了介紹向後查找,因此就使用向後查找的方法吧。當你瞭解了向後查找,我相信你在不少須要正則表達式的地方使用會更加靈活。測試
String content = "http://www.freemethod.cn"; //匹配http://而後向後查找全部的字符 String regex = "(?<=http://).*";
這裏就是首先匹配到http://而後以它做爲邊界匹配後面的.*,匹配的結果是www.freemethod.cn。 注意:向前匹配和向後匹配除了表達式的一點區別,還有就是它們的位置區別url
##回溯 回溯應該是正則表達式中最重要的內容之一了,回溯就是標記分組而後引用前面的分組。好比咱們有一個字符串:"[attach]7219[/attach]",咱們在標籤開始匹配到了attach,要在標籤結束再一次使用attach標籤怎麼辦了。若是這個還不太明顯,那麼在來一個字符串看一下,"[a*]7219[/a*]"這個字符串咱們想匹配以a開始的標籤中的數字,顯然正則表達是不能這麼寫,由於這麼寫可能會匹配到[ab]7219[/ac],這個時候咱們就須要回溯引用第一個正則表達式匹配到的字符串。就能夠想下面同樣code
String content = "freemethod[attach]7219[/attach]fremethod[align]left[/align]"; String regex = "\\[(a.*)\\].*\\[/\\1\\]";
正則表達式中的\1就是對第一個小括號中匹配的內容的引用,同理\2就是對第二個小括號匹配的內容的引用,以此類推\3,\4 \5...像上面的表達式就能夠匹配到,[attach]7219[/attach]和[align]left[/align]這兩個標籤。htm
##經過先後查找與回溯提取標籤中的內容 上面已經介紹了先後查找和回溯,下面就介紹一下經過先後查找和回溯來匹配標籤中的內容。假設咱們有下面的html代碼遞歸
<h1>H1<h2>這是和h2中的內容</h2>H1</h1>
如今咱們要提取h2標籤中的內容:"這是和h2中的內容",咱們的正則表達式應該怎麼寫呢?,這裏咱們就使用先後查找和回溯來匹配。首先前後查找匹配,< h2 >,(?<=<(h2)>),而後匹配h2中的內容.* ,連起來(?<=<(h2)>).*,而後經過向前查找加回溯應用匹配h2標籤結束。(?=</\1>)。完整的正則以下:rem
String content = "<h1>H1<h2>這是和h2中的內容</h2>H1</h1>"; String regex = "(?<=<(h2)>).*(?=</\\1>)";
若是你想挑戰一下,能夠試嘗試計算一下下面的正則表達式的結果:字符串
public void testTrace() { String content = "<h1>外部h1開始<h2>這是和h2中的內容<h2>h2中的h2</h2>h2結束</h2><h1>h1中的h1</h1>外部h1結束</h1>"; String regex = "<h2>.*?</h2>"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*(?=</\\1>)"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*(?=</h\\d>)"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*?(?=</h\\d>)"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*?(?=</\\1>)"; execute(content, regex); }
若是你以爲還不夠複雜,能夠嘗試讓字符串的嵌套和遞歸更加深一點,再一次挑戰嘗試一下,你會發如今比較複雜的嵌套中使用先後查找和回溯是多麼的美妙。
##完整測試代碼
import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.Test; public class TagExtractTest { /** * 先後查找回溯結合提取標籤中的內容 */ @Test public void testTagExtract() { // String content = "iejoiodi[attach]7219[/attach]djiojeio"; // String regex = "(?<=\\[(attach)\\])\\d*(?=\\[/\\1\\])"; String content = "<h1>H1<h2>這是和h2中的內容</h2>H1</h1>"; String regex = "(?<=<(h2)>).*(?=</\\1>)"; execute(content, regex); } /** * 向前查找(?=) */ @Test public void testLookForward() { String content = "178$"; //匹配$而後查找$前面的數字(\\d+) String regex = "\\d+(?=\\$)"; execute(content, regex); content = "2016年:雞翅 15元 雞腿 10元 雞爪 5元"; regex = "\\d+(?=元)"; execute(content, regex); } /** * 向後查找(?<=) */ @Test public void testLookBehind() { String content = "http://www.freemethod.cn"; //匹配http://而後向後查找全部的字符 String regex = "(?<=http://).*"; // String content = "$178"; // String regex = "(?<=\\$)\\d+"; execute(content, regex); } /** * 回溯 \\1 回溯匹配第一個組,\\2回溯匹配第二個分組依次類推 * 表達式中的一個()表示一個分組 */ @Test public void testBackTrace() { String content = "abcfreemethod[attach]7219[/attach]bcadde"; String regex = "\\[(attach)\\]\\d+\\[/\\1\\]"; execute(content, regex); content = "freemethod[attach]7219[/attach]fremethod[align]left[/align]"; regex = "\\[(a.*)\\].*\\[/\\1\\]"; execute(content, regex); } /** * 先後查找結合使用 */ @Test public void testLookAround() { String content = "[attach]7219[/attach]"; String regex = "(?<=\\[(attach)\\])\\d*(?=\\[/attach\\])"; execute(content, regex); } @Test public void testTrace() { String content = "<h1>外部h1開始<h2>這是和h2中的內容<h2>h2中的h2</h2>h2結束</h2><h1>h1中的h1</h1>外部h1結束</h1>"; String regex = "<h2>.*?</h2>"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*(?=</\\1>)"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*(?=</h\\d>)"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*?(?=</h\\d>)"; execute(content, regex); System.out.println("--------------------------"); regex = "(?<=<(h\\d)>).*?(?=</\\1>)"; execute(content, regex); } private void execute(String content,String regex) { System.out.println("content:"+content); System.out.println("regex:"+regex); Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(content); while(matcher.find()) { System.out.println(matcher.group()); } } }