|
@@ -1,145 +0,0 @@
|
|
|
-package org.leumasjaffe.format;
|
|
|
|
|
-
|
|
|
|
|
-import java.util.HashMap;
|
|
|
|
|
-import java.util.Objects;
|
|
|
|
|
-import java.util.regex.Matcher;
|
|
|
|
|
-import java.util.regex.Pattern;
|
|
|
|
|
-
|
|
|
|
|
-import lombok.AccessLevel;
|
|
|
|
|
-import lombok.experimental.FieldDefaults;
|
|
|
|
|
-
|
|
|
|
|
-@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
|
|
|
|
|
-public class StringFormatter {
|
|
|
|
|
- private static final class NameMap extends HashMap<String, Object> {
|
|
|
|
|
- /**
|
|
|
|
|
- *
|
|
|
|
|
- */
|
|
|
|
|
- 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);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private static final class FmtStateMachine {
|
|
|
|
|
- final StringBuilder str;
|
|
|
|
|
-
|
|
|
|
|
- String fmt;
|
|
|
|
|
- Object[] args;
|
|
|
|
|
- int currentIdx;
|
|
|
|
|
- final NameMap named;
|
|
|
|
|
- int lastCh, endPos = 0;
|
|
|
|
|
-
|
|
|
|
|
- FmtStateMachine(String fmt, Object... args) {
|
|
|
|
|
- this(fmt, 0, args, new NameMap(args), '\0');
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- FmtStateMachine(String fmt, int idx, Object[] args, NameMap named, int lastCh) {
|
|
|
|
|
- this.str = new StringBuilder(fmt.length());
|
|
|
|
|
- this.fmt = fmt;
|
|
|
|
|
- this.currentIdx = idx;
|
|
|
|
|
- this.args = args;
|
|
|
|
|
- this.named = named;
|
|
|
|
|
- this.lastCh = lastCh;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- FmtStateMachine formatMain() {
|
|
|
|
|
- int lpos = 0;
|
|
|
|
|
- for (int pos = fmt.indexOf('{'); pos != -1 && hasMore(pos); lpos = pos+1, pos = fmt.indexOf('{', lpos)) {
|
|
|
|
|
- str.append(fmt.substring(lpos, pos).replaceAll("}}", "}"));
|
|
|
|
|
- int epos = fmt.indexOf('}', pos);
|
|
|
|
|
-
|
|
|
|
|
- if (fmt.charAt(pos+1) == '{') {
|
|
|
|
|
- // Literal '{'
|
|
|
|
|
- str.append('{');
|
|
|
|
|
- epos = pos + 1;
|
|
|
|
|
- } else if (epos == pos+1) {
|
|
|
|
|
- // Unmarked '{}' -> get the next argument
|
|
|
|
|
- str.append(getToken(null));
|
|
|
|
|
- } else {
|
|
|
|
|
- epos = formatToken(pos, epos);
|
|
|
|
|
- }
|
|
|
|
|
- pos = epos;
|
|
|
|
|
- }
|
|
|
|
|
- str.append(remaining(lpos).replaceAll("}}", "}"));
|
|
|
|
|
- return this;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private String remaining(int lpos) {
|
|
|
|
|
- this.endPos = fmt.indexOf(lastCh, lpos);
|
|
|
|
|
- return lastCh == '\0' ? fmt.substring(lpos) : fmt.substring(lpos, endPos++);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private boolean hasMore(int pos) {
|
|
|
|
|
- return lastCh == '\0' || pos < fmt.indexOf(lastCh);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private int formatToken(int pos, int epos) {
|
|
|
|
|
- final String token = fmt.substring(++pos, epos);
|
|
|
|
|
- // If token contains a '.', use reflection?
|
|
|
|
|
- // If token starts with '%', make it a c-format expression
|
|
|
|
|
- if (token.indexOf('?') != -1) {
|
|
|
|
|
- final int b1 = fmt.indexOf('?', pos)+1;
|
|
|
|
|
- boolean _if = getConditionToken(token, b1-pos-1);
|
|
|
|
|
- FmtStateMachine then = new FmtStateMachine(fmt.substring(b1), currentIdx, args, named, ':').formatMain();
|
|
|
|
|
- FmtStateMachine els = new FmtStateMachine(fmt.substring(then.endPos+b1), then.currentIdx, args, named, '}').formatMain();
|
|
|
|
|
- currentIdx = els.currentIdx;
|
|
|
|
|
- epos = els.endPos+then.endPos+b1-1;
|
|
|
|
|
- str.append(_if ? then : els);
|
|
|
|
|
- } else {
|
|
|
|
|
- str.append(getToken(token));
|
|
|
|
|
- }
|
|
|
|
|
- return epos;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private boolean getConditionToken(final String token, final int end) {
|
|
|
|
|
- final String cond = token.substring(0, end);
|
|
|
|
|
- Matcher matcher = Pattern.compile("^(\\d*|[a-zA-Z_]+)(>=?|<=?|!=|==?)(\\d+)$").matcher(cond);
|
|
|
|
|
- if (matcher.matches()) {
|
|
|
|
|
- final int cmp = ((Integer) getToken(matcher.group(1))).compareTo(Integer.valueOf(matcher.group(3)));
|
|
|
|
|
- switch (matcher.group(2)) {
|
|
|
|
|
- case "=" : return cmp == 0;
|
|
|
|
|
- case "==": return cmp == 0;
|
|
|
|
|
- case "!=": return cmp != 0;
|
|
|
|
|
- case "<" : return cmp < 0;
|
|
|
|
|
- case "<=": return cmp <= 0;
|
|
|
|
|
- case ">" : return cmp > 0;
|
|
|
|
|
- case ">=": return cmp >= 0;
|
|
|
|
|
- default: throw new IllegalStateException();
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- return (Boolean) getToken(cond);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private Object getToken(final String token) {
|
|
|
|
|
- if (token == null || token.isEmpty()) {
|
|
|
|
|
- return args[currentIdx++];
|
|
|
|
|
- } else if (Character.isDigit(token.charAt(0))) {
|
|
|
|
|
- return args[Integer.parseInt(token)];
|
|
|
|
|
- } else {
|
|
|
|
|
- return named.get(token);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public String toString() {
|
|
|
|
|
- return str.toString();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- String fmt;
|
|
|
|
|
-
|
|
|
|
|
- public StringFormatter(String logFmtString) {
|
|
|
|
|
- Objects.requireNonNull(logFmtString);
|
|
|
|
|
- this.fmt = logFmtString;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public String format(Object... args) {
|
|
|
|
|
- return new FmtStateMachine(fmt, args).formatMain().toString();
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|