import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.*;
public class Main {
public static void main(String[] args) throws Exception {
// JSON文字列の定義
String jsonString = "{\n" +
"\"apiVer1\":\"$$(TEST_NO1)\",\n" +
"\"apiver2\":\"$$(TEST_NO2 HEAD:11)\",\n" +
"\"norma\":\"testValue\",\n" +
"\"apiver\":\"14\",\n" +
"\"normal2\":\"testValue2\",\n" +
"\"apiPerson\":{\n" +
"\"apiVer3\":\"$$(TEST_NO3 HEAD:13)\",\n" +
"\"kokyaku\":\"$$(kokyakuNo)\",\n" +
"\"apiVer4\":\"$$(TEST_NO4 HEAD:24)\"\n" +
"},\n" +
"\"apiFunds\":{\n" +
"\"apiVer5\":\"$$(TEST_NO5 HEAD:26)\",\n" +
"\"apiVer6\":\"$$(TEST_NO6 ERA:yymmdd)\",\n" +
"\"apiVer7\":\"$$(TEST_NO7 ERA:yymm)\",\n" +
"\"apiVer8\":\"$$(TEST_NO8 IFNA:0/)\",\n" +
"\"apiVer9\":\"$$(TEST_NO9 IFNA:0/*)\",\n" +
"\"apiVer10\":\"$$(TEST_NO10 IFNA:1234567890/66666)\",\n" +
"\"apiVer11\":\"$$(TEST_NO11 IFNA:7890123/89012345)\"\n" +
"}\n" +
"}";
// テストデータのマップを定義
Map<String, String> bindDateMap = new HashMap<>();
bindDateMap.put("TEST_NO1", "test1Value");
bindDateMap.put("TEST_NO2", "123456789012345");
bindDateMap.put("TEST_NO3", "123456789012345");
bindDateMap.put("TEST_NO4", "123456789012345678901234567");
bindDateMap.put("TEST_NO5", "123456789012345678901234567");
bindDateMap.put("TEST_NO6", "19940505");
bindDateMap.put("TEST_NO7", "123456");
bindDateMap.put("TEST_NO8", "8"); // 空文字を設定
bindDateMap.put("TEST_NO9", "100");
bindDateMap.put("TEST_NO10", null);
bindDateMap.put("TEST_NO11", "200");
bindDateMap.put("kokyakuNo", "");
// JSON文字列からキーと対応する加工処理のパターンを抽出
Map<String, String> extractedKeyPatternMap = extractKeyPatterns(jsonString);
// 最終的な結果を格納するマップの定義
Map<String, Object> req = new HashMap<>();
// 抽出したキーを使って値を加工し、結果マップに格納
for (Map.Entry<String, String> entry : extractedKeyPatternMap.entrySet()) {
String jsonKey = entry.getKey(); // JSONのキー
String patternOrValue = entry.getValue(); // $$()内の加工処理のパターンまたはそのままの値
if (patternOrValue.startsWith("$$(")) {
String pattern = patternOrValue.substring(3, patternOrValue.length() - 1); // $$()を取り除く
String bindKey = pattern.split(" ")[0]; // 加工処理のパターンからテスト番号を取得
// ①キーが存在しているかどうかチェック
if (!bindDateMap.containsKey(bindKey)) {
throw new RuntimeException("500000エラー: " + bindKey + " がbindDateMapに存在しません");
}
// ② 加工処理のパターン内に半角スペースがあるかチェック
if (pattern.contains(" ")) {
String value = bindDateMap.get(bindKey); // テストデータマップから値を取得
if (value == null || value.isEmpty() || "0".equals(value)) { // 空文字チェックの追加
value = ""; // 値がnullまたは"0"の場合には空文字を格納
}
String processedValue = processValue(pattern, value); // 値を加工
addNestedValue(req, jsonKey, processedValue); // 結果をreqマップに追加
} else {
addNestedValue(req, jsonKey, bindDateMap.get(bindKey)); // 加工処理のパターンなしで値を追加
}
} else {
addNestedValue(req, jsonKey, patternOrValue); // 値をそのままreqマップに追加
}
}
// reqマップをJSON文字列に変換
ObjectMapper objectMapper = new ObjectMapper();
String jsonResultString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(req);
System.out.println(jsonResultString);
}
/**
* JSON文字列からキーと加工処理のパターンを抽出するメソッド。
*
* @param jsonString 処理するJSON文字列
* @return キーと加工処理のパターンのマップ
* @throws Exception JSONパースエラーが発生した場合
*/
public static Map<String, String> extractKeyPatterns(String jsonString) throws Exception {
Map<String, String> keyPatternMap = new HashMap<>();
// JSON文字列をパース
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(jsonString);
// 再帰的にJSONノードを処理してキーと加工処理のパターンを抽出
extractPatternsRecursive(rootNode, "", keyPatternMap);
return keyPatternMap;
}
/**
* 再帰的にJSONノードを処理してキーと加工処理のパターンを抽出するメソッド。
*
* @param node JSONノード
* @param parentKey 親キー
* @param keyPatternMap キーと加工処理のパターンのマップ
*/
private static void extractPatternsRecursive(JsonNode node, String parentKey, Map<String, String> keyPatternMap) {
if (node.isObject()) {
// JSONオブジェクトの場合、各フィールドを処理
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> field = fields.next();
String currentKey = parentKey.isEmpty() ? field.getKey() : parentKey + "." + field.getKey();
extractPatternsRecursive(field.getValue(), currentKey, keyPatternMap);
}
} else if (node.isTextual()) {
// テキストノードの場合、加工処理のパターンを抽出
String text = node.asText();
Pattern pattern = Pattern.compile("\\$\\$\\((.*?)\\)");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
keyPatternMap.put(parentKey, matcher.group(0)); // $$()の加工処理のパターンを含めて取得
} else {
keyPatternMap.put(parentKey, text); // 加工処理のパターンが見つからない場合はそのまま取得
}
}
}
/**
* キーに基づいて値を加工するメソッド。
*
* @param key 加工処理のパターン
* @param value 元の値
* @return 加工された値
* @throws ParseException 日付のパースエラーが発生した場合
*/
public static String processValue(String key, String value) throws ParseException {
if (key.contains("HEAD:")) {
return processHead(key, value);
} else if (key.contains("ERA:yymmdd")) {
// ERA:yymmddの場合、和暦に変換
return convertToJapaneseEra(value, "yyyyMMdd");
} else if (key.contains("ERA:yymm")) {
// ERA:yymmの場合、和暦に変換
return convertToJapaneseEra(value, "yyyyMM");
} else if (key.contains("IFNA:")) {
return processIfna(key, value);
} else {
throw new RuntimeException("500000エラー: " + key + " に該当しません");
}
}
/**
* HEADパターンに基づいて値を加工するメソッド。
*
* @param key 加工処理のパターン
* @param value 元の値
* @return 加工された値
*/
public static String processHead(String key, String value) {
String[] parts = key.split("HEAD:");
if (parts.length != 2 || !parts[1].matches("\\d+")) {
throw new RuntimeException("500000エラー: " + key + " のHEADパターンが不正です");
}
int headLength = Integer.parseInt(parts[1]);
if (value.length() <= headLength) {
return value; // valueがheadLength以下の場合はそのまま返す
}
return value.substring(0, headLength);
}
/**
* IFNAパターンに基づいて値を加工するメソッド。
*
* @param key 加工処理のパターン
* @param value 元の値
* @return 加工された値
*/
public static String processIfna(String key, String value) {
// keyの形式チェック
if (!key.matches(".*IFNA:(\\d*|\\s*)/(\\d*|\\s*|\\*)")) {
throw new RuntimeException("500000エラー: " + key + " のIFNAパターンが不正です");
}
String[] parts = key.split("IFNA:")[1].split("/");
if (parts.length != 2) {
// "IFNA:0/" のようなパターンを許容するための修正
if (parts.length == 1 && key.endsWith("/")) {
parts = new String[]{parts[0], ""};
} else {
throw new RuntimeException("500000エラー: " + key + " のIFNAパターンが不正です");
}
}
// 空文字の場合には空文字を設定
String nullValueReplacement = parts[0].isEmpty() ? "" : parts[0];
String nonNullValueReplacement = parts[1].isEmpty() ? "" : parts[1];
if (key.contains("/*")) {
return (value == null || value.isEmpty()) ? nullValueReplacement : value;
} else {
return (value == null || value.isEmpty()) ? nullValueReplacement : nonNullValueReplacement;
}
}
/**
* 西暦を和暦に変換するメソッド。
*
* @param date 西暦の日付文字列
* @param format 日付のフォーマット
* @return 和暦の日付文字列
* @throws ParseException 日付のパースエラーが発生した場合
*/
public static String convertToJapaneseEra(String date, String format) throws ParseException {
// 数字かつ、桁数が8桁または6桁かをチェック
if (!date.matches("\\d{6}|\\d{8}")) {
throw new RuntimeException("500000エラー: 日付の形式が不正です - " + date);
}
SimpleDateFormat sdf = new SimpleDateFormat(format);
Date westernDate = sdf.parse(date);
Calendar calendar = Calendar.getInstance();
calendar.setTime(westernDate);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // Calendarの月は0から始まるため+1
int day = calendar.get(Calendar.DAY_OF_MONTH);
String eraYear;
if (format.equals("yyyyMMdd")) {
if (year > 2019 || (year == 2019 && (month > 5 || (month == 5 && day >= 1)))) {
// 令和 (2019年5月1日から)
eraYear = String.format("%02d", year - 2018); // 年が1桁の場合に先頭に0を付ける
return "5" + eraYear + String.format("%02d%02d", month, day);
} else if (year > 1989 || (year == 1989 && (month > 1 || (month == 1 && day >= 8)))) {
// 平成 (1989年1月8日から)
eraYear = String.format("%02d", year - 1988); // 年が1桁の場合に先頭に0を付ける
return "4" + eraYear + String.format("%02d%02d", month, day);
} else if (year > 1926 || (year == 1926 && (month > 12 || (month == 12 && day >= 25)))) {
// 昭和 (1926年12月25日から)
eraYear = String.format("%02d", year - 1925); // 年が1桁の場合に先頭に0を付ける
return "3" + eraYear + String.format("%02d%02d", month, day);
} else if (year > 1912 || (year == 1912 && (month > 7 || (month == 7 && day >= 30)))) {
// 大正 (1912年7月30日から)
eraYear = String.format("%02d", year - 1911); // 年が1桁の場合に先頭に0を付ける
return "2" + eraYear + String.format("%02d%02d", month, day);
} else if (year > 1868 || (year == 1868 && (month > 1 || (month == 1 && day >= 25)))) {
// 明治 (1868年1月25日から)
eraYear = String.format("%02d", year - 1867); // 年が1桁の場合に先頭に0を付ける
return "1" + eraYear + String.format("%02d%02d", month, day);
} else {
// 上記以外の場合、未("0")
eraYear = "00"; // 年が1桁の場合に先頭に0を付ける
return "0" + eraYear + String.format("%02d%02d", month, day);
}
} else if (format.equals("yyyyMM")) {
if (year > 2019 || (year == 2019 && month >= 5)) {
// 令和 (2019年5月から)
eraYear = String.format("%02d", year - 2018); // 年が1桁の場合に先頭に0を付ける
return "5" + eraYear + String.format("%02d", month);
} else if ((year > 1989) || (year == 1989 && month >= 2) || (year == 2019 && month < 5)) {
// 平成 (1989年2月から2019年4月まで)
eraYear = String.format("%02d", year - 1988); // 年が1桁の場合に先頭に0を付ける
return "4" + eraYear + String.format("%02d", month);
} else if ((year > 1926) || (year == 1927 && month >= 1) || (year == 1989 && month < 2)) {
// 昭和 (1927年1月から1989年1月まで)
if (year == 1927 && month == 1) {
eraYear = String.format("%02d", year - 1926); // 年が1桁の場合に先頭に0を付ける
} else {
eraYear = String.format("%02d", year - 1926 + 1); // 1927年1月は昭和1年1月とする
}
return "3" + eraYear + String.format("%02d", month);
} else if ((year > 1912) || (year == 1912 && month >= 8) || (year == 1926 && month < 12)) {
// 大正 (1912年8月から1926年12月まで)
eraYear = String.format("%02d", year - 1911); // 年が1桁の場合に先頭に0を付ける
return "2" + eraYear + String.format("%02d", month);
} else if ((year > 1868) || (year == 1868 && month >= 2) || (year == 1912 && month < 8)) {
// 明治 (1868年2月から1912年7月まで)
eraYear = String.format("%02d", year - 1867); // 年が1桁の場合に先頭に0を付ける
return "1" + eraYear + String.format("%02d", month);
} else {
// 上記以外の場合、未("0")
eraYear = "00"; // 年が1桁の場合に先頭に0を付ける
return "0" + eraYear + String.format("%02d", month);
}
} else {
throw new RuntimeException("500000エラー: " + format + " は該当しません");
}
}
/**
* ネストされたキーに基づいて値を設定するメソッド。
*
* @param map 設定するマップ
* @param key ドットで区切られたキー
* @param value 設定する値
*/
private static void addNestedValue(Map<String, Object> map, String key, Object value) {
String[] keys = key.split("\\.");
Map<String, Object> currentMap = map;
for (int i = 0; i < keys.length - 1; i++) {
String k = keys[i];
if (!currentMap.containsKey(k) || !(currentMap.get(k) instanceof Map)) {
currentMap.put(k, new HashMap<>());
}
currentMap = (Map<String, Object>) currentMap.get(k);
}
currentMap.put(keys[keys.length - 1], value);
}
}
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme