This is pretty early, and well... probably full of bugs... It is just a proof of concept at this point, but seems to work.
Python style template/formatting in Java
// >>> '{0}, {1}, {2}'.format('a', 'b', 'c')
// 'a, b, c'
String str = format("{0}, {1}, {2}", "a", "b", "c");
print("fmt1", str);
//fmt is the short form of format
str = fmt("{0}, {1}, {2}", "a", "b", "c");
print("fmt2", str);
// >>> '{}, {}, {}'.format('a', 'b', 'c') # 2.7+ only
// 'a, b, c'
str = fmt("{}, {}, {}", "a", "b", "c");
print("fmt3", str);
// >>> '{2}, {1}, {0}'.format('a', 'b', 'c')
// 'c, b, a'
str = fmt("{2}, {1}, {0}", "a", "b", "c");
print("fmt4", str);
// >>> '{2}, {1}, {0}'.format(*'abc') # unpacking argument sequence
// 'c, b, a'
str = fmt("{2}, {1}, {0}", array("abc"));
print("fmt5", str);
str = fmt("{2}, {1}, {0}", (Object[]) array(1, 2, 3));
print("fmt6", str);
str = fmt("{2}, {1}, {0}", oarray(1, 2, 3));
print("fmt7", str);
str = fmt("{2}, {1}, {0}", oar(1, 2, 3));
print("fmt8", str);
// >>> '{0}{1}{0}'.format('abra', 'cad') # arguments' indices can be
// repeated
// 'abracadabra'
str = fmt("{0}{1}{0}", "abra", "cad");
print("fmt9", str);
// >>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N',
// longitude='-115.81W')
// 'Coordinates: 37.24N, -115.81W'
str = fmt("Coordinates: {latitude}, {longitude}",
mp("latitude", "37.24N", "longitude", "-115.81W"));
print("fmt10", str);
// >>> "{1:0>+10.3f},{1}".format(2.2,3.0)
// '0000+3.000,3.0'
str = fmt("{1:2.2f},{1}", 2.2, 3.0);
print("fmt11", str);
str = fmt("Coordinates: {latitude:2.2f}, {longitude}",
mp("latitude", 37.24, "longitude", -115.81));
print("fmt12", str);
str = fmt("{1[0]:2.2f},{1}", 2.2, ls(2.2, 3.0));
print("fmt13", str);
str = fmt("0={0},1={1},1.my2={1.my2:2.2f}", 2.2,
mp("my", 2.2, "my2", 3.0));
print("fmt14", str);
str = fmt("{0}, fn={0.firstName}, salary={0.salary:2.2f}",
emp("Rick", "Hightower", 1000.0));
print("fmt15", str);
str = fmt(
"{0}, fn={emps[0].firstName}, salary={emps[0].salary:2.2f}",
mp("emps",
ls(emp("Rick", "Hightower", 1000.0),
emp("Bob", "Hightower", 7000.0))));
print("fmt16", str);
print();
print();
str = fmt(
"a={test}\n" + "b={test.emps}\n" + "c={test.emps[0]}\n"
+ "d={test.emps[0].firstName}\n"
+ "e={test.emps[0].salary:2.2f}",
mp("test",
mp("emps",
ls(emp("Rick", "Hightower", 1000.0),
emp("Bob", "Hightower", 7000.0)))));
print("fmt17", str);
...
static Employee emp(String firstName, String lastName, double salary) {
return new Employee(firstName, lastName, salary);
}
public static class Employee {
String firstName;
String lastName;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setSalary(double salary) {
this.salary = salary;
}
double salary;
public Employee(String firstName, String lastName, double salary) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
}
@Override
public String toString() {
return "Employee [firstName=" + firstName + ", lastName="
+ lastName + ", salary=" + salary + "]";
}
}
Output
fmt1 a, b, c
fmt2 a, b, c
fmt3 a, b, c
fmt4 c, b, a
fmt5 c, b, a
fmt6 3, 2, 1
fmt7 3, 2, 1
fmt8 3, 2, 1
fmt9 abracadabra
fmt10 Coordinates: 37.24N, -115.81W
fmt11 3.00,3.0
fmt12 Coordinates: 37.24, -115.81
fmt13 2.20,[2.2, 3.0]
fmt14 0=2.2,1={my2=3.0, my=2.2},1.my2=3.00
fmt15 Employee [firstName=Rick, lastName=Hightower, salary=1000.0], fn=Rick, salary=1000.00
fmt16 null, fn=Rick, salary=1000.00
fmt17 a={emps=[Employee [firstName=Rick, lastName=Hightower, salary=1000.0], Employee [firstName=Bob, lastName=Hightower, salary=7000.0]]}
b=[Employee [firstName=Rick, lastName=Hightower, salary=1000.0], Employee [firstName=Bob, lastName=Hightower, salary=7000.0]]
c=Employee [firstName=Rick, lastName=Hightower, salary=1000.0]
d=Rick
e=1000.00
Implementation
public static String mfmt(String str, Map<?, ?> map) {
return mapFormat(str, map);
}
public static String mapFormat(String str, Map<?, ?> map) {
StringBuilder builder = new StringBuilder(str.length());
StringBuilder contents = new StringBuilder(32);
StringBuilder formatRulesContents = new StringBuilder(32);
char[] charArray = str.toCharArray();
for (int index=0; index<charArray.length; index++) {
char c = charArray[index];
if (c=='{') {
contents.setLength(0);
formatRulesContents.setLength(0);
index++;
boolean formatRules=false;
for (;index<charArray.length && c!='}'; index++) {
c = charArray[index];
if (c=='[' || c=='!' || c==':' || c=='.') {
formatRules=true;
}
if (c!='}') {
if (!formatRules) {
contents.append(c);
} else {
formatRulesContents.append(c);
}
}
}
if (!formatRules) {
builder.append(map.get(contents.toString()));
} else {
builder.append(formatRule(map.get(contents.toString()), formatRulesContents.toString()));
}
index--;
} else {
builder.append(c);
}
}
return builder.toString();
}
public static String fmt(String str, Object... args) {
return format(str, args);
}
public static String format(String str, Object... args) {
if (args.length==1) {
if (args[0] instanceof char[]) {
return cformat(str, (char[]) args[0]);
} else if (args[0] instanceof Map) {
return mapFormat(str, (Map<?,?>)args[0]);
} else {
return arrayFormat(str, args);
}
} else {
return arrayFormat(str, args);
}
}
public static String arfmt(String str, Object... args) {
return format(str, args);
}
public static String arrayFormat(String str, Object... args) {
StringBuilder builder = new StringBuilder(str.length());
StringBuilder contents = new StringBuilder(32);
StringBuilder formatRulesContents = new StringBuilder(32);
int argIndexKeeper = 0;
int argIndex=-666;
char[] charArray = str.toCharArray();
for (int index=0; index<charArray.length; index++) {
char c = charArray[index];
if (c=='{') {
contents.setLength(0);
formatRulesContents.setLength(0);
index++;
boolean formatRules=false;
for (;index<charArray.length && c!='}'; index++) {
c = charArray[index];
if (c=='[' || c=='!' || c==':' || c=='.') {
formatRules=true;
}
if (c!='}') {
if (!formatRules) {
contents.append(c);
} else {
formatRulesContents.append(c);
}
}
}
String sindex = contents.toString().trim();
if (sindex.isEmpty()) {
argIndex = argIndexKeeper;
if (!formatRules) {
builder.append(args[argIndex].toString());
} else {
builder.append(formatRule(args[argIndex], formatRulesContents.toString()));
}
argIndexKeeper++;
} else {
argIndex = Integer.parseInt(sindex);
if (!formatRules) {
builder.append(args[argIndex].toString());
} else {
builder.append(formatRule(args[argIndex], formatRulesContents.toString()));
}
}
index--;
} else {
builder.append(c);
}
}
return builder.toString();
}
private static String formatRule(Object object, String rule) {
StringBuilder format = new StringBuilder(16);
StringBuilder idx = new StringBuilder(16);
List <Object> idxs = new ArrayList<Object>(16);
char[] charArray = rule.toCharArray();
boolean hasFormat = false;
boolean hasIndex = false;
boolean hasDotIndex = false;
for (int index=0; index< charArray.length; index++) {
char c = charArray[index];
if(hasFormat) {
format.append(c);
} else if (hasIndex) {
if (c == ']') {
idxs.add(Integer.parseInt(idx.toString()));
hasIndex = false;
} else {
idx.append(c);
}
} else if (hasDotIndex) {
if (c=='[' || c == '.' || c == ':') {
idxs.add(idx.toString());
hasDotIndex = false;
} else {
idx.append(c);
if (index+1 == charArray.length) {
idxs.add(idx.toString());
hasDotIndex = false;
}
}
}
if (c == ':') {
hasFormat = true;
format.setLength(0);
} else if (c == '[') {
hasIndex = true;
idx.setLength(0);
} else if (c == '.') {
hasDotIndex = true;
idx.setLength(0);
}
}
if (hasFormat) {
format.insert(0, '%');
}
for (Object oindex : idxs) {
if (oindex instanceof Integer) {
int index = (Integer)oindex;
if (object.getClass().isArray()) {
object = Array.get(object, index);
} else if (object instanceof List) {
object = index(((List<?>)object), index);
} else {
object = null;
}
} else {
String key = (String)oindex;
if (object instanceof Map) {
@SuppressWarnings("unchecked")
Map <String,?> map = (Map<String, ?>) object;
object = map.get(key);
} else {
object.getClass().getDeclaredMethods();
Class<? extends Object> clz = object.getClass();
outer:
while (clz!=Object.class) {
Method[] methods = clz.getDeclaredMethods();
for (Method method : methods) {
method.setAccessible(true);
if (method.getParameterTypes().length==0 && method.getName().toLowerCase().endsWith(key.toLowerCase())
&& (method.getName().startsWith("is") || method.getName().startsWith("get") ||
method.getName().length()==key.length())
) {
try {
object = method.invoke(object, (Object[])null);
break outer;
} catch (Exception ex) {
continue;
}
}
}
Field[] declaredFields = clz.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
if (field.getName().equals(key)) {
try {
object = field.get(object);
break outer;
} catch (Exception ex) {
break;
}
}
}
clz = clz.getSuperclass();
}
}
}
}
if (object==null) {
return "";
} else if (hasFormat) {
return String.format(format.toString(), object);
} else {
return object.toString();
}
}
public static String cfmt(String str, char... args) {
return cformat(str, args);
}
public static String cformat(String str, char... args) {
StringBuilder builder = new StringBuilder(str.length());
StringBuilder contents = new StringBuilder(32);
int argIndexKeeper = 0;
int argIndex=-666;
char[] charArray = str.toCharArray();
for (int index=0; index<charArray.length; index++) {
char c = charArray[index];
if (c=='{') {
contents.setLength(0);
index++;
for (;index<charArray.length && c!='}'; index++) {
c = charArray[index];
if (c!='}') {
contents.append(c);
}
}
String sindex = contents.toString().trim();
if (sindex.isEmpty()) {
argIndex = argIndexKeeper;
builder.append(args[argIndex]);
argIndexKeeper++;
} else {
argIndex = Integer.parseInt(sindex);
builder.append(args[argIndex]);
}
index--;
} else {
builder.append(c);
}
}
return builder.toString();
}
No comments:
Post a Comment