|
@@ -28,6 +28,7 @@ import java.time.format.DateTimeFormatter;
|
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
import java.util.Locale;
|
|
import java.util.Locale;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
+import java.util.Objects;
|
|
|
import java.util.TimeZone;
|
|
import java.util.TimeZone;
|
|
|
import java.util.function.BiFunction;
|
|
import java.util.function.BiFunction;
|
|
|
import java.util.function.Function;
|
|
import java.util.function.Function;
|
|
@@ -67,15 +68,18 @@ public final class ResolveLocale {
|
|
|
DecimalFormatSymbols us = DecimalFormatSymbols.getInstance(Locale.US);
|
|
DecimalFormatSymbols us = DecimalFormatSymbols.getInstance(Locale.US);
|
|
|
|
|
|
|
|
putFormat("", "", r -> new FGeneric(r));
|
|
putFormat("", "", r -> new FGeneric(r));
|
|
|
-
|
|
|
|
|
- // number : 2 + 3 5
|
|
|
|
|
- // date : 2 + 8 10
|
|
|
|
|
- // time : 2 + 8 10
|
|
|
|
|
- // hex : 1 + 2 3
|
|
|
|
|
- // metric : 1 + 4 5
|
|
|
|
|
- // binary : 1 + 6 7
|
|
|
|
|
- // : 40 x language
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // number of entries:
|
|
|
|
|
+ // text : 2 + 0 2
|
|
|
|
|
+ // number : 2 + 5 7
|
|
|
|
|
+ // date : 2 + 8 10
|
|
|
|
|
+ // time : 2 + 8 10
|
|
|
|
|
+ // hex : 1 + 2 3
|
|
|
|
|
+ // metric : 1 + 4 5
|
|
|
|
|
+ // binary : 1 + 6 7
|
|
|
|
|
+ // : 44 x language
|
|
|
|
|
+
|
|
|
|
|
+ putText(locale);
|
|
|
putNumber(us, locale);
|
|
putNumber(us, locale);
|
|
|
putDate(locale);
|
|
putDate(locale);
|
|
|
putTime(locale);
|
|
putTime(locale);
|
|
@@ -85,6 +89,11 @@ public final class ResolveLocale {
|
|
|
putChoice();
|
|
putChoice();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void putText(Locale locale) {
|
|
|
|
|
+ putFormat("format", (r,p) -> new FPrintf(r, p));
|
|
|
|
|
+ putFormat("text", (r,p) -> new FText(r, p, locale));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private void putNumber(DecimalFormatSymbols us, Locale locale) {
|
|
private void putNumber(DecimalFormatSymbols us, Locale locale) {
|
|
|
putFormat("number", (r,p) -> new FNumber(r, new DecimalFormat(p,us)));
|
|
putFormat("number", (r,p) -> new FNumber(r, new DecimalFormat(p,us)));
|
|
|
putFormat("number", "", r -> new FNumber(r, DecimalFormat.getInstance(locale)));
|
|
putFormat("number", "", r -> new FNumber(r, DecimalFormat.getInstance(locale)));
|
|
@@ -674,5 +683,95 @@ public final class ResolveLocale {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ private static final class FPrintf implements ResolveFormat.Token {
|
|
|
|
|
+
|
|
|
|
|
+ private final ResolvePattern resolver;
|
|
|
|
|
+
|
|
|
|
|
+ private final String pattern;
|
|
|
|
|
+
|
|
|
|
|
+ public FPrintf(ResolvePattern resolver, String pattern) {
|
|
|
|
|
+ this.resolver = resolver;
|
|
|
|
|
+ this.pattern = pattern;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public String regex() {
|
|
|
|
|
+ return "(.+)";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void append(Appendable target, Object context) throws IOException {
|
|
|
|
|
+ target.append(String.format(pattern, resolver.get(context)));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void parse(String source, Object context) {
|
|
|
|
|
+ resolver.set(context, LexicalCast.cast(source, resolver.type(context)));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static final class FText implements ResolveFormat.Token {
|
|
|
|
|
+
|
|
|
|
|
+ private final ResolvePattern resolver;
|
|
|
|
|
+ private final Locale locale;
|
|
|
|
|
+ private final boolean left;
|
|
|
|
|
+ private final int min;
|
|
|
|
|
+ private final int max;
|
|
|
|
|
+ private final boolean upper;
|
|
|
|
|
+ private final boolean lower;
|
|
|
|
|
+
|
|
|
|
|
+ public FText(ResolvePattern resolver, String options, Locale locale) {
|
|
|
|
|
+ this.resolver = resolver;
|
|
|
|
|
+ this.locale = locale;
|
|
|
|
|
+ Matcher hit = Pattern.compile("(?<padd>[-+])?(?<min>[0-9]+)(?:.(?<max>[0-9]+))?(?<upper>[uU])?(?<lower>[lLsS])?").matcher(options);
|
|
|
|
|
+ if(!hit.matches()) {
|
|
|
|
|
+ throw new IllegalArgumentException("Invalid text format: " + options);
|
|
|
|
|
+ }
|
|
|
|
|
+ this.left = Objects.equals("-", hit.group("padd"));
|
|
|
|
|
+ this.min = Integer.parseInt(ValueUtils.or(hit.group("min"), "0"));
|
|
|
|
|
+ this.max = Integer.parseInt(ValueUtils.or(hit.group("max"), "0"));
|
|
|
|
|
+ this.upper = hit.group("upper") != null;
|
|
|
|
|
+ this.lower = hit.group("lower") != null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public String regex() {
|
|
|
|
|
+ return "(.+)";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void append(Appendable target, Object context) throws IOException {
|
|
|
|
|
+ String text = String.valueOf(resolver.get(context));
|
|
|
|
|
+ if(upper) {
|
|
|
|
|
+ text = text.toUpperCase(locale);
|
|
|
|
|
+ }
|
|
|
|
|
+ if(lower) {
|
|
|
|
|
+ text = text.toLowerCase(locale);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (max > 0 && text.length() > max) {
|
|
|
|
|
+ text = text.substring(0, max);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (text.length() < min) {
|
|
|
|
|
+ CharSequence padding = StringUtils.repeat(min - text.length(), ' ');
|
|
|
|
|
+ if (left) {
|
|
|
|
|
+ target.append(text).append(padding);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ target.append(padding).append(text);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ target.append(text);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void parse(String source, Object context) {
|
|
|
|
|
+ resolver.set(context, LexicalCast.cast(source, resolver.type(context)));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
|
|
|
}
|
|
}
|