MessageFormatter
这是一个字符串格式化工具,主要完成两个功能
1.对于字符串“ hello {0}, {1}“在转换过程中会将{0}替换为所传参数数组下标为0的参数值,{1}则替换为下标为1的参数值。好处是支持任意的下标值,而jdk自带的MessageFormatter下标值只能是0-9
调用方式MessageFormatter.formatter(str, params);
2.将字符串中${xx},替换为一个外部的值,比如默认的MessageFormatter遇到${xx}后会试图通过 System.getProperty(xx)获取值,然后将${xx}替换为获取之后的值,外部值获取主要通过PropertySource来取,构造 器可以传入PropertySource的实现类。
看代码:
/**
*
* @author zhaoming
*
*/
public class MessageFormatter {
private PropertySource source;
private static final char DELIM_START = '{';
private static final char DELIM_START_LEN = 1;
private static final char DELIM_END = '}';
private static final char DELIM_END_LEN = 1;
private static final char ESCAPE_CHAR = '\\';
private static final char REF_CHAR = '$';
public MessageFormatter(PropertySource source) {
if (source == null) {
source = new SystemPropertySource();
} else {
this.source = source;
}
}
public MessageFormatter() {
source = new SystemPropertySource();
}
public String format(String pattern) {
return this.format(pattern, null);
}
public String format(String pattern, Object[] args) {
return this.format(pattern, args, 0);
}
private String format(String pattern, Object[] args, int argIdx) {
try {
if (pattern == null) {
return pattern;
}
if (args == null) {
args = new Object[0];
}
StringBuilder sb = new StringBuilder(pattern.length() + 20);
int start = 0;
int sidx = -1;
int eidx = -1;
String argStr = "";
while (start < pattern.length() && (sidx = pattern.indexOf(DELIM_START, start)) >= 0) {
if (hasEscapeChar(pattern, sidx)) {
if (hasDoubleEscapeChar(pattern, sidx)) {
sb.append(pattern, start, sidx - 1);
} else {
sb.append(pattern, start, sidx - 1).append(DELIM_START);
start = sidx + DELIM_START_LEN;
continue;
}
} else {
sb.append(pattern, start, sidx);
}
eidx = pattern.indexOf(DELIM_END, sidx);
if (eidx == -1) {
sb.append(pattern, sidx, pattern.length());
start = pattern.length();
} else {
argStr = pattern.substring(sidx + DELIM_START_LEN, eidx).trim();
if (argStr.isEmpty() || isNumeric(argStr)) {
appendIndexParam(sb, getArgInt(argStr, argIdx++), args, argStr);
} else {
appendRefParam(sb, argIdx, args, argStr);
}
start = eidx + DELIM_END_LEN;
}
}
if (start < pattern.length()) {
sb.append(pattern, start, pattern.length());
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return pattern;
}
private boolean isNumeric(String s) {
int len = s.length();
for (int i = 0; i < len; i++) {
if (!Character.isDigit(s.charAt(i))) {
return false;
}
}
return true;
}
private int getArgInt(String param, int v) {
try {
if ("".equals(param)) {
return v;
}
return Integer.parseInt(param);
} catch (NumberFormatException e) {
}
return -1;
}
private void appendRefParam(StringBuilder sb, int argIdx, Object[] args, String orgParam) {
int len = sb.length();
boolean isRef = true;
if (len == 0 || sb.charAt(len - 1) != REF_CHAR) {
isRef = false;
}
if (hasEscapeChar(sb, len - 1) && !hasDoubleEscapeChar(sb, len - 1)) {
isRef = false;
}
if (isRef) {
String v = source.getProperty(orgParam);
if (v != null) {
sb.setLength(len - 1);
sb.append(this.format(v, args, argIdx));
return;
}
}
sb.append(DELIM_START).append(orgParam).append(DELIM_END);
}
private void appendIndexParam(StringBuilder sb, int argIdx, Object[] args, String orgParam) {
if (argIdx < 0 || argIdx >= args.length) {
sb.append(DELIM_START).append(orgParam).append(DELIM_END);
} else {
deeplyAppendParam(sb, args[argIdx], new HashMap