在说具体的内容之前先来了解一下什么是向前查找,向后查找与回溯。我们通过一下小的例子来理解一下。具体的代码附录在最后。
##向前查找 Java中向前查找的正则表达式是(?=),更加具体的就是 要匹配内容的正则(?=匹配的边界的正则)。来一个具体的例子,比如我们有一个具体的字符串2016年:鸡翅 15元 鸡腿 10元 鸡爪 5元,现在我们要取出里面的价格15 10 5,而不要2016,显然我们不能直接\d+来匹配。 我们很容易发现规律,我们需要提取单位‘元’前面的数字,但是我们不想要单位‘元’,怎么办,这里就可以使用向前查找了。
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。 注意:向前匹配和向后匹配除了表达式的一点区别,还有就是它们的位置区别
##回溯 回溯应该是正则表达式中最重要的内容之一了,回溯就是标记分组然后引用前面的分组。比如我们有一个字符串:"[attach]7219[/attach]",我们在标签开始匹配到了attach,要在标签结束再一次使用attach标签怎么办了。如果这个还不太明显,那么在来一个字符串看一下,"[a*]7219[/a*]"这个字符串我们想匹配以a开始的标签中的数字,显然正则表达是不能这么写,因为这么写可能会匹配到[ab]7219[/ac],这个时候我们就需要回溯引用第一个正则表达式匹配到的字符串。就可以想下面一样
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]这两个标签。
##通过前后查找与回溯提取标签中的内容 上面已经介绍了前后查找和回溯,下面就介绍一下通过前后查找和回溯来匹配标签中的内容。假设我们有下面的html代码
<h1>H1<h2>这是和h2中的内容</h2>H1</h1>
现在我们要提取h2标签中的内容:"这是和h2中的内容",我们的正则表达式应该怎么写呢?,这里我们就使用前后查找和回溯来匹配。首先先后查找匹配,< h2 >,(?<=<(h2)>),然后匹配h2中的内容.* ,连起来(?<=<(h2)>).*,然后通过向前查找加回溯应用匹配h2标签结束。(?=</\1>)。完整的正则如下:
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());
}
}
}
来源:oschina
链接:https://my.oschina.net/u/2474629/blog/760990