Java字符串格式化工具

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<Object[], Object>());
    	}
    }
    
    private void deeplyAppendParam (StringBuilder sb, Object o, Map<Object[], Object> seenMap) {
    	if (o == null) {
            sb.append("null");
            return;
        }
        if (!o.getClass().isArray()) {
        	appendToString(sb, o);
        } else {
        	if (o.getClass() == Object[].class) {
        		objectArrayAppend(sb,  (Object[]) o, seenMap);
        	} else {
        		int len = Array.getLength(o);
        		sb.append("[");
        		for (int i = 0; i < len; i++) {
        			appendToString(sb, Array.get(o, i));
        			if (i != len - 1) {
        				sb.append(", ");
        			}
        		}
        		sb.append(']');
        	}
        }
    }
    
    private void objectArrayAppend(StringBuilder sb, Object[] a, Map<Object[], Object> seenMap) {
    	sb.append('[');
        if (!seenMap.containsKey(a)) {
            seenMap.put(a, null);
            final int len = a.length;
            for (int i = 0; i < len; i++) {
            	deeplyAppendParam(sb, a[i], seenMap);
                if (i != len - 1)
                    sb.append(", ");
            }
            seenMap.remove(a);
        } else {
            sb.append("...");
        }
        sb.append(']');
    }
    
    private void appendToString(StringBuilder sb, Object o) {
    	try {
			if(o == null) {
				sb.append("null");
			} else {
				sb.append(o.toString());
			}
		} catch (Exception e) {
			sb.append("[failed toString]");
		}
    }
    
    private boolean hasEscapeChar(StringBuilder pattern, int idx) {
    	if (idx > 0 && pattern.charAt(idx - 1) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    private boolean hasEscapeChar(String pattern, int idx) {
    	if (idx > 0 && pattern.charAt(idx - 1) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    private boolean hasDoubleEscapeChar(StringBuilder pattern, int idx) {
    	if (idx >= 2 && pattern.charAt(idx - 2) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    private boolean hasDoubleEscapeChar(String pattern, int idx) {
    	if (idx >= 2 && pattern.charAt(idx - 2) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    class SystemPropertySource implements PropertySource {

		@Override
		public String getProperty(String key) {
			try {
				return System.getProperty(key);
			} catch (Exception e) {
			}
			return null;
		}
    	
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值