Java 通配符替换的几种实现方式

Java常用通配符的替换及定制实现。

  • String.format(“hi, %s”, “uname”)
  • log.info(“hi, {}”, “uname”)

自行实现

思路:

  • 方法体 format(Object… value);
  • 实现方式:字符匹配替换,Matcher类find。
    Pattern类的作用在于编译正则表达式后创建一个匹配模式.
    Matcher类使用Pattern实例提供的模式信息对正则表达式进行匹配.
    matcher.appendReplacement() 与 matcher.appendTail().
    前者是将当前匹配子串替换为指定字符串,并且将替换后的子串,以及其之前到上次匹配子串之后的字符串段添加到一个 StringBuffer 对象里。后者则将最后一次匹配工作后剩余的字符串添加到一个 StringBuffer 对象里。

Code实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
private StringBuilder buffer;

private static final String namedParameterPrefix = ":";

private static final String regex = "[{]\\d*[}]";

private static Pattern fsPattern = Pattern.compile(regex);

public StringWrapper(String str) {
buffer = new StringBuilder(str);
}

public StringWrapper(StringBuilder s){
buffer = s;
}

private Map<String, Object> namedParameter = new HashMap<String, Object>(32);

public StringWrapper setParameter(String namedParameter, Object value) {
this.namedParameter.put(namedParameter, value);
return this;
}

public StringWrapper setProperties(Map<String, Object> map) {
namedParameter = map;
return this;
}

public String format(Object... value) {
if (namedParameter.size() > 0) {
Set<String> keySet = namedParameter.keySet();
for (String key : keySet) {
Object objValue = namedParameter.get(key);
String parameterName = namedParameterPrefix + key;
buffer = new StringBuilder(buffer.toString().replace(parameterName,
(objValue == null ? "" : objValue.toString())));
}
}
int len = value.length;
if (len == 0)
return buffer.toString();
StringBuffer sb = new StringBuffer();
Matcher matcher = fsPattern.matcher(buffer);
while (matcher.find()) {
String group = matcher.group();
int index = getIndex(group);
if (index > len - 1)
throw new RuntimeException("format的输入参数没有第" + (index + 1) + "个参数值!");
Object objValue = value[index];
matcher.appendReplacement(sb, (objValue == null ? "" : objValue.toString()));
}
matcher.appendTail(sb);
return sb.toString();
}

public int getIndex(String group) {
if (group == null || group.trim().equals(""))
throw new RuntimeException("regex匹配的group为空!");
int len = group.length();
return NumberUtils.toInt(group.substring(1, len - 1));
}

public static void main(String[] args) {

String ttt = "hello world, :username, Time:{0}!";
StringWrapper w = new StringWrapper(ttt);
System.out.println(w.setParameter("username", "lsq").format(new Date().getTime()));
}

执行结果如下

hello world, lsq, Time:1526978430709!

String.format实现过程

  • 分析源码得到其通过java.util.Formatter实现。
  • 代码比较简洁,贴出用来作为对比。
  • 先通过Matcher从字符串中查找分隔符,拆分成FOrmatString数组,在进行分段print输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static String format(String format, Object... args) {
return new Formatter().format(format, args).toString();
}

public Formatter format(Locale l, String format, Object ... args) {
ensureOpen();

// index of last argument referenced
int last = -1;
// last ordinary index
int lasto = -1;

FormatString[] fsa = parse(format);
for (int i = 0; i < fsa.length; i++) {
FormatString fs = fsa[i];
int index = fs.index();
try {
switch (index) {
case -2: // fixed string, "%n", or "%%"
fs.print(null, l);
break;
case -1: // relative index
if (last < 0 || (args != null && last > args.length - 1))
throw new MissingFormatArgumentException(fs.toString());
fs.print((args == null ? null : args[last]), l);
break;
case 0: // ordinary index
lasto++;
last = lasto;
if (args != null && lasto > args.length - 1)
throw new MissingFormatArgumentException(fs.toString());
fs.print((args == null ? null : args[lasto]), l);
break;
default: // explicit index
last = index - 1;
if (args != null && last > args.length - 1)
throw new MissingFormatArgumentException(fs.toString());
fs.print((args == null ? null : args[last]), l);
break;
}
} catch (IOException x) {
lastException = x;
}
}
return this;
}

org.slf4j.Logger.info实现过程

  • org.slf4j.helpers.MessageFormatter.arrayFormat()

    逻辑

总结

  • Formatter是广泛被用到的格式化方法,它能让一些东西变得更加有规范,很多超市小票,信息单,用这个方法来格式化就显得很不错。

  • String.format 这个方法很实用,但如果是大批量进行字符串格式化,就需要考虑到性能方面的问题,因为每次调用 format() 方法都会 new 一个 Formatter 对象。而在 Java 中频繁创建对象需要大量时间,而且还要花时间对这些对象进行GC。

------本文结束感谢阅读------
显示评论
0%