在说具体的内容以前先来了解一下什么是向前查找,向后查找与回溯。咱们经过一下小的例子来理解一下。具体的代码附录在最后。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()); } } }