import java.io.*; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ReadDataUtil { private static final Pattern LINE_FORMAT = Pattern.compile("^\\d+(\\.\\d+)?, *[A-Za-z \\d:.-]+(, *[-+]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?){6}, *$"); private static final Pattern DATE_COLUMN_FORMAT = Pattern.compile("^A\\.D\\. (?\\d{4})-(?[A-Z][a-z]{2})-(?[0-3]\\d) \\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$"); private static final Pattern DATE_FORMAT_YYYY_MMM_DD = Pattern.compile("^(?\\d{4})-(?[A-Z][a-z]{2})-(?[0-3]\\d)$"); /** * Reads the position and velocity vector on the specified 'day' from the file with the * specified 'path', and sets position and current velocity of 'b' accordingly. If * successful the method returns 'true'. If the specified 'day' was not found in the file, * 'b' is unchanged and the method returns 'false'. * The file format is validated before reading the state. * Lines before the line "$$SOE" and after the line "$$EOE" the are ignored. Each line of the * file between the line "$$SOE" and the line "$$EOE" is required to have the following format: * JDTDB, TIME, X, Y, Z, VX, VY, VZ * where JDTDB is interpretable as a 'double' value, TIME is a string and X, Y, Z, VX, VY and * VZ are interpretable as 'double' values. JDTDB can be ignored. The character ',' must only * be used as field separator. If the file is not found, an exception of the class * 'StateFileNotFoundException' is thrown. If it does not comply with the format described * above, the method throws an exception of the class 'StateFileFormatException'. Both * exceptions are subtypes of 'IOException'. * Precondition: b != null, path != null, day != null and has the format YYYY-MM-DD. */ public static boolean readConfiguration(NamedBody b, String path, String day) throws IOException { State state = State.Pre; try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(path))) { Scanner lines = new Scanner(in); long lineNum = 0; while (lines.hasNextLine() && state != State.Post) { lineNum++; String line = lines.nextLine(); State nextState = state.next(line); if (state == State.In && nextState == State.In) { Matcher m = LINE_FORMAT.matcher(line); if (!m.matches()) { throw new StateFileFormatException(path, lineNum); } String[] rows = line.split(", *"); String date; try { date = convertDateColumn(rows[1]); } catch (IllegalArgumentException e) { throw new StateFileFormatException(path, lineNum); } if (date.equals(day)) { try { double x = Double.parseDouble(rows[2]); // [km] double y = Double.parseDouble(rows[3]); // [km] double z = Double.parseDouble(rows[4]); // [km] double vx = Double.parseDouble(rows[5]); // [km/s] double vy = Double.parseDouble(rows[6]); // [km/s] double vz = Double.parseDouble(rows[7]); // [km/s] b.setState(new Vector3(x * 1000, y * 1000, z * 1000), new Vector3(vx * 1000, vy * 1000, vz * 1000)); } catch (NumberFormatException e) { throw new StateFileFormatException(path, lineNum); } return true; } } state = nextState; } } catch (IOException e) { if (e instanceof FileNotFoundException) { throw new StateFileNotFoundException(path); } else { throw e; } } return false; } private static String convertDateColumn(String column) { Matcher m = DATE_COLUMN_FORMAT.matcher(column); if (!m.matches()) { throw new IllegalArgumentException(); } return m.group("year") + "-" + convertMonth(m.group("month")) + "-" + m.group("day"); } public static String convertDate(String date) { Matcher m = DATE_FORMAT_YYYY_MMM_DD.matcher(date); if (!m.matches()) { throw new IllegalArgumentException(); } return m.group("year") + "-" + convertMonth(m.group("month")) + "-" + m.group("day"); } private static String convertMonth(String month) { return switch (month) { case "Jan" -> "01"; case "Feb" -> "02"; case "Mar" -> "03"; case "Apr" -> "04"; case "May" -> "05"; case "Jun" -> "06"; case "Jul" -> "07"; case "Aug" -> "08"; case "Sep" -> "09"; case "Oct" -> "10"; case "Nov" -> "11"; case "Dec" -> "12"; default -> throw new IllegalArgumentException(); }; } private enum State { Pre, In, Post; public State next(String line) { switch (this) { case Pre: if (line.equals("$$SOE")) return In; break; case In: if (line.equals("$$EOE")) return Post; break; case Post: break; } return this; } } }