//matcher.appendReplacement方法含义解读
//从输入序列中读取字符,从追加位置开始,并将它们添加到给定的字符串缓冲区中。该方法在读取到前一个匹配之前的最后一个字符(即索引 start() - 1 处的字符)后停止。
//将给定的替换字符串添加到字符串缓冲区中。
//将此匹配器的追加位置设置为最后一个匹配字符的索引加一,即设置为 end()。
//替换字符串可以包含对前一次匹配期间捕获的子序列的引用:
//每个出现的 ${name} 或 $g 将分别被替换为计算相应 group(name) 或 group(g) 的结果。
//对于 $g,$ 后的第一个数字始终被视为组引用的一部分。如果后续数字能形成合法的组引用,则它们会被纳入 g 中。
//只有数字 ‘0’ 到 ‘9’ 被视为组引用的潜在组成部分。
//例如,如果第二个组匹配字符串 “foo”,那么传递替换字符串 “$2bar” 将导致 “foobar” 被追加到字符串缓冲区中。
//要在替换字符串中包含字面意义的美元符号($),可以在其前面加上反斜线(\$)。
//请注意,替换字符串中的反斜线(\)和美元符号($)可能导致结果与将其视为字面替换字符串时不同。如上所述,美元符号可能被视为对捕获子序列的引用,而反斜线用于转义替换字符串中的字面字符。
}
package cn.richinfo.digital.util;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* java正则表达式命名捕获组示例及模版变量替换实战
*/
public class NamedGroupExample {
public static void main(String[] args) {
useNameGroup();
replaceTempalteVar();
}
/**
* 使用命名捕获组
*/
private static void useNameGroup() {
String text = "姓名: 张三, 年龄: 25, 城市: 北京";
// 使用命名捕获组 (?<name>pattern) 【jdk1.7 提供 】
String regex = "姓名:\\s(?<name>\\S+),\\s年龄:\\s(?<age>\\d+),\\s城市:\\s(?<city>\\S+)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println("使用命名组:");
System.out.println("姓名: " + matcher.group("name"));
System.out.println("年龄: " + matcher.group("age"));
System.out.println("城市: " + matcher.group("city"));
System.out.println("\n使用编号组:");
System.out.println("组 1: " + matcher.group(1));
System.out.println("组 2: " + matcher.group(2));
System.out.println("组 3: " + matcher.group(3));
}
}
/**
* 命名捕获组的实际应用:替换模版变量
*/
public static void replaceTempalteVar() {
// 模拟从配置文件读取的模板
StringBuffer configTemplate = new StringBuffer();
configTemplate.append("server:");
configTemplate.append("name: ${serverName}");
configTemplate.append("port: ${serverPort}");
configTemplate.append("environment: ${env}");
configTemplate.append("database:");
configTemplate.append("host: ${dbHost}");
configTemplate.append("name: ${dbName}");
// 模拟用户提供的配置值
Map<String, String> configValues = new HashMap<>();
configValues.put("serverName", "MyAppServer");
configValues.put("serverPort", "8080");
configValues.put("env", "production");
configValues.put("dbHost", "localhost");
configValues.put("dbName", "myapp_db");
configValues.put("dbName", "${aaa}");
// 匹配 ${key} 格式的占位符
//使用命名捕获组 (?<name>pattern)
String regex = "\\$\\{(?<key>\\w+)\\}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(configTemplate.toString());
StringBuffer result = new StringBuffer();
System.out.println("=== 模板渲染 ===");
System.out.println("原始模板:");
System.out.println(configTemplate);
while (matcher.find()) {
//命名捕获组匹配到值,等价于matcher.group(1); 在还没有命名捕获组时,捕获组就是用下标获取值
String key = matcher.group("key");
//String key = matcher.group(1);//等价
String value = configValues.get(key);
String replacement="";
if (value != null) {
// 注意:这里直接使用值替换,不是用占位符
replacement=value;
System.out.format("替换 ${%s} →%s%n" ,key, value);
} else {
// 如果找不到值,保留原占位符
replacement=matcher.group();
}
//每个出现的 ${name} 或 $g 将分别被替换为计算相应 group(name) 或 group(g) 的结果
//Matcher.quoteReplacement(replacement)
// 转义美元符和反斜杠,防止map的value中出出现美元符如:${aaa},不转义会报错No group with name {aaa}
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(result);
System.out.println("\n渲染结果:");
System.out.println(result.toString());
}
//matcher.appendReplacement方法含义解读
//从输入序列中读取字符,从追加位置开始,并将它们添加到给定的字符串缓冲区中。该方法在读取到前一个匹配之前的最后一个字符(即索引 start() - 1 处的字符)后停止。
//将给定的替换字符串添加到字符串缓冲区中。
//将此匹配器的追加位置设置为最后一个匹配字符的索引加一,即设置为 end()。
//替换字符串可以包含对前一次匹配期间捕获的子序列的引用:
//每个出现的 ${name} 或 $g 将分别被替换为计算相应 group(name) 或 group(g) 的结果。
//对于 $g,$ 后的第一个数字始终被视为组引用的一部分。如果后续数字能形成合法的组引用,则它们会被纳入 g 中。
//只有数字 '0' 到 '9' 被视为组引用的潜在组成部分。
//例如,如果第二个组匹配字符串 "foo",那么传递替换字符串 "$2bar" 将导致 "foobar" 被追加到字符串缓冲区中。
//要在替换字符串中包含字面意义的美元符号($),可以在其前面加上反斜线(\$)。
//请注意,替换字符串中的反斜线(\)和美元符号($)可能导致结果与将其视为字面替换字符串时不同。如上所述,美元符号可能被视为对捕获子序列的引用,而反斜线用于转义替换字符串中的字面字符。
}
Java正则命名捕获与模板替换
5005

被折叠的 条评论
为什么被折叠?



