package org.leumasjaffe.format; import java.util.HashMap; import java.util.Objects; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true) public class StringFormatter { private static final class NameMap extends HashMap { /** * */ private static final long serialVersionUID = -2243574068000774442L; NameMap(Object... args) { for (Object arg : args) { Objects.requireNonNull(arg); if (arg instanceof Named) { put(((Named) arg).getName(), arg); } } } } String fmt; public StringFormatter(String logFmtString) { this.fmt = logFmtString; } public String format(Object... args) { final StringBuilder str = new StringBuilder(fmt.length()); int currentIdx = 0; final NameMap named = new NameMap(args); int lpos = 0; for (int pos = fmt.indexOf('{'); pos != -1; lpos = pos+1, pos = fmt.indexOf('{', lpos)) { str.append(fmt.substring(lpos, pos)); int epos = fmt.indexOf('}', pos); if (fmt.charAt(pos+1) == '{') { str.append(fmt.substring(++pos, ++epos)); } else if (epos == pos+1) { str.append(args[currentIdx++]); } else { final String token = fmt.substring(pos+1, epos); if (Character.isDigit(token.charAt(0))) { str.append(args[Integer.parseInt(token)]); } else { // In theory, I could add a format-mode here too str.append(named.get(token)); } } pos = epos; } str.append(fmt.substring(lpos)); return str.toString(); } }