ฉันสร้างคลาส util / helper (ใช้ jdk 8) ซึ่งสามารถจัดรูปแบบสตริงและแทนที่ตัวแปรที่เกิดขึ้น
เพื่อจุดประสงค์นี้ฉันใช้วิธีการ "appendReplacement" ของ Matchers ซึ่งทำการทดแทนและวนซ้ำเฉพาะส่วนที่ได้รับผลกระทบของสตริงรูปแบบเท่านั้น
คลาสตัวช่วยไม่ได้จัดทำเอกสาร javadoc เป็นอย่างดี ฉันจะเปลี่ยนแปลงสิ่งนี้ในอนาคต;) อย่างไรก็ตามฉันแสดงความคิดเห็นบรรทัดที่สำคัญที่สุด (ฉันหวังว่า)
public class FormatHelper {
//Prefix and suffix for the enclosing variable name in the format string.
//Replace the default values with any you need.
public static final String DEFAULT_PREFIX = "${";
public static final String DEFAULT_SUFFIX = "}";
//Define dynamic function what happens if a key is not found.
//Replace the defualt exception with any "unchecked" exception type you need or any other behavior.
public static final BiFunction<String, String, String> DEFAULT_NO_KEY_FUNCTION =
(fullMatch, variableName) -> {
throw new RuntimeException(String.format("Key: %s for variable %s not found.",
variableName,
fullMatch));
};
private final Pattern variablePattern;
private final Map<String, String> values;
private final BiFunction<String, String, String> noKeyFunction;
private final String prefix;
private final String suffix;
public FormatHelper(Map<String, String> values) {
this(DEFAULT_NO_KEY_FUNCTION, values);
}
public FormatHelper(
BiFunction<String, String, String> noKeyFunction, Map<String, String> values) {
this(DEFAULT_PREFIX, DEFAULT_SUFFIX, noKeyFunction, values);
}
public FormatHelper(String prefix, String suffix, Map<String, String> values) {
this(prefix, suffix, DEFAULT_NO_KEY_FUNCTION, values);
}
public FormatHelper(
String prefix,
String suffix,
BiFunction<String, String, String> noKeyFunction,
Map<String, String> values) {
this.prefix = prefix;
this.suffix = suffix;
this.values = values;
this.noKeyFunction = noKeyFunction;
//Create the Pattern and quote the prefix and suffix so that the regex don't interpret special chars.
//The variable name is a "\w+" in an extra capture group.
variablePattern = Pattern.compile(Pattern.quote(prefix) + "(\\w+)" + Pattern.quote(suffix));
}
public static String format(CharSequence format, Map<String, String> values) {
return new FormatHelper(values).format(format);
}
public static String format(
CharSequence format,
BiFunction<String, String, String> noKeyFunction,
Map<String, String> values) {
return new FormatHelper(noKeyFunction, values).format(format);
}
public static String format(
String prefix, String suffix, CharSequence format, Map<String, String> values) {
return new FormatHelper(prefix, suffix, values).format(format);
}
public static String format(
String prefix,
String suffix,
BiFunction<String, String, String> noKeyFunction,
CharSequence format,
Map<String, String> values) {
return new FormatHelper(prefix, suffix, noKeyFunction, values).format(format);
}
public String format(CharSequence format) {
//Create matcher based on the init pattern for variable names.
Matcher matcher = variablePattern.matcher(format);
//This buffer will hold all parts of the formatted finished string.
StringBuffer formatBuffer = new StringBuffer();
//loop while the matcher finds another variable (prefix -> name <- suffix) match
while (matcher.find()) {
//The root capture group with the full match e.g ${variableName}
String fullMatch = matcher.group();
//The capture group for the variable name resulting from "(\w+)" e.g. variableName
String variableName = matcher.group(1);
//Get the value in our Map so the Key is the used variable name in our "format" string. The associated value will replace the variable.
//If key is missing (absent) call the noKeyFunction with parameters "fullMatch" and "variableName" else return the value.
String value = values.computeIfAbsent(variableName, key -> noKeyFunction.apply(fullMatch, key));
//Escape the Map value because the "appendReplacement" method interprets the $ and \ as special chars.
String escapedValue = Matcher.quoteReplacement(value);
//The "appendReplacement" method replaces the current "full" match (e.g. ${variableName}) with the value from the "values" Map.
//The replaced part of the "format" string is appended to the StringBuffer "formatBuffer".
matcher.appendReplacement(formatBuffer, escapedValue);
}
//The "appendTail" method appends the last part of the "format" String which has no regex match.
//That means if e.g. our "format" string has no matches the whole untouched "format" string is appended to the StringBuffer "formatBuffer".
//Further more the method return the buffer.
return matcher.appendTail(formatBuffer)
.toString();
}
public String getPrefix() {
return prefix;
}
public String getSuffix() {
return suffix;
}
public Map<String, String> getValues() {
return values;
}
}
คุณสามารถสร้างอินสแตนซ์ของคลาสสำหรับแผนที่เฉพาะด้วยค่า (หรือคำนำหน้าคำต่อท้ายหรือ noKeyFunction) เช่น:
Map<String, String> values = new HashMap<>();
values.put("firstName", "Peter");
values.put("lastName", "Parker");
FormatHelper formatHelper = new FormatHelper(values);
formatHelper.format("${firstName} ${lastName} is Spiderman!");
// Result: "Peter Parker is Spiderman!"
// Next format:
formatHelper.format("Does ${firstName} ${lastName} works as photographer?");
//Result: "Does Peter Parker works as photographer?"
ยิ่งไปกว่านั้นคุณสามารถกำหนดสิ่งที่จะเกิดขึ้นหากคีย์ในค่า Map ขาดหายไป (ทำงานได้ทั้งสองวิธีเช่นชื่อตัวแปรผิดในรูปแบบสตริงหรือคีย์ที่ขาดหายไปในแผนที่) พฤติกรรมเริ่มต้นเป็นข้อยกเว้นที่ไม่ถูกตรวจสอบโยน (ไม่ถูกตรวจสอบเพราะฉันใช้ฟังก์ชั่นเริ่มต้น jdk8 ซึ่งไม่สามารถจัดการข้อยกเว้นตรวจสอบการตรวจสอบ) เช่น:
Map<String, String> map = new HashMap<>();
map.put("firstName", "Peter");
map.put("lastName", "Parker");
FormatHelper formatHelper = new FormatHelper(map);
formatHelper.format("${missingName} ${lastName} is Spiderman!");
//Result: RuntimeException: Key: missingName for variable ${missingName} not found.
คุณสามารถกำหนดพฤติกรรมที่กำหนดเองในการโทรคอนสตรัคเช่น:
Map<String, String> values = new HashMap<>();
values.put("firstName", "Peter");
values.put("lastName", "Parker");
FormatHelper formatHelper = new FormatHelper(fullMatch, variableName) -> variableName.equals("missingName") ? "John": "SOMETHING_WRONG", values);
formatHelper.format("${missingName} ${lastName} is Spiderman!");
// Result: "John Parker is Spiderman!"
หรือมอบอำนาจให้กลับไปที่ค่าเริ่มต้นไม่มีพฤติกรรมที่สำคัญ:
...
FormatHelper formatHelper = new FormatHelper((fullMatch, variableName) -> variableName.equals("missingName") ? "John" :
FormatHelper.DEFAULT_NO_KEY_FUNCTION.apply(fullMatch,
variableName), map);
...
เพื่อการจัดการที่ดีขึ้นนอกจากนี้ยังมีวิธีการคงที่เช่น:
Map<String, String> values = new HashMap<>();
values.put("firstName", "Peter");
values.put("lastName", "Parker");
FormatHelper.format("${firstName} ${lastName} is Spiderman!", map);
// Result: "Peter Parker is Spiderman!"