在Java开发中,提取已知起始和结束标记之间的可变长度子字符串是常见需求,比如从HTML片段中提取标签内的内容,或者从日志中提取特定标记之间的信息。正则表达式能够用简洁的规则完成这类匹配任务,避免手动遍历字符的繁琐操作。
核心类与基础概念
Java中处理正则表达式的核心类是java.util.regex.Pattern和java.util.regex.Matcher。Pattern用于编译正则表达式规则,Matcher用于对目标字符串进行匹配操作。
要实现提取起始和结束标记之间的内容,需要用到正则表达式的捕获组语法,用圆括号()包裹需要提取的内容部分,同时要注意处理标记的转义问题,因为很多标记本身是正则表达式的特殊字符。
正则规则编写要点
假设起始标记为start,结束标记为end,要提取两者之间的可变长度内容,基础正则规则可以写为:
start(.*?)end
规则说明:
start和end是字面匹配起始和结束标记(.*?)是捕获组,.匹配任意字符,*表示匹配0次或多次,?表示非贪婪匹配,即尽可能少地匹配字符,避免跨多个结束标记匹配
如果起始或结束标记包含正则特殊字符,比如<、>、.、*等,需要使用反斜杠进行转义,在Java字符串中反斜杠本身需要转义,所以要写两个反斜杠。
完整实现代码示例
以下是一个提取<div>和</div>之间内容的完整示例:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.ArrayList;
import java.util.List;
public class RegexExtractDemo {
public static void main(String[] args) {
// 目标字符串,包含多个需要提取的片段
String targetStr = "<div>第一个div内容</div>其他文本<div>第二个div内容</div>";
// 起始标记和结束标记
String startMark = "<div>";
String endMark = "</div>";
// 构建正则规则,对标记中的特殊字符进行转义
// 这里<和>不是正则特殊字符,不需要转义,如果是.等特殊字符需要加\
String regex = Pattern.quote(startMark) + "(.*?)" + Pattern.quote(endMark);
// 编译正则规则,设置DOTALL模式让.可以匹配换行符
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
Matcher matcher = pattern.matcher(targetStr);
// 存储提取结果的列表
List<String> resultList = new ArrayList<>();
// 循环匹配所有符合条件的内容
while (matcher.find()) {
// group(0)是整个匹配到的字符串,group(1)是第一个捕获组的内容,即标记之间的部分
String extractedContent = matcher.group(1);
resultList.add(extractedContent);
}
// 输出结果
System.out.println("提取到的内容:");
for (String content : resultList) {
System.out.println(content);
}
}
}
代码说明:
- 使用
Pattern.quote()方法包裹起始和结束标记,可以自动对标记中的正则特殊字符进行转义,避免手动转义的麻烦 - 添加
Pattern.DOTALL模式后,正则中的.可以匹配包括换行符在内的所有字符,适合多行内容的提取场景 matcher.find()会依次查找所有匹配的子串,通过循环可以提取出所有符合条件的内容
常见问题与注意事项
贪婪匹配与非贪婪匹配的选择
如果正则中使用(.*)而不是(.*?),就是贪婪匹配,会尽可能多地匹配字符,比如目标字符串是<div>a</div><div>b</div>,贪婪匹配会直接匹配到a</div><div>b,而(.*?)会分别匹配到a和b,需要根据实际需求选择。
标记包含换行符的情况
如果起始或结束标记本身包含换行符,需要在编译正则时添加Pattern.MULTILINE模式,或者调整正则规则适配换行场景。
无匹配结果的处理
如果目标字符串中没有符合规则的片段,matcher.find()会返回false,提取结果列表会是空的,实际使用中可以根据业务需求添加对应的处理逻辑。
总结
使用Java正则表达式提取已知起始和结束标记间的可变长度子字符串,核心在于正确编写非贪婪匹配的正则规则,合理使用Pattern和Matcher类,同时注意特殊字符的转义和多场景模式的适配。这种方法比手动遍历字符更高效,代码也更简洁,适合各类字符串提取场景。