SimpleTimeStampedTableParser.java

  1. /* Copyright 2002-2013 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.data;

  18. import java.io.BufferedReader;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.InputStreamReader;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.regex.Matcher;
  25. import java.util.regex.Pattern;

  26. import org.apache.commons.math3.exception.util.DummyLocalizable;
  27. import org.orekit.errors.OrekitException;
  28. import org.orekit.errors.OrekitMessages;
  29. import org.orekit.time.TimeStamped;

  30. /**
  31.  * Parser for simple tables containing {@link TimeStamped time stamped} data.
  32.  * @param <T> the type of time stamped data (i.e. parsed table rows)
  33.  * @author Luc Maisonobe
  34.  * @since 6.1
  35.  */
  36. public class SimpleTimeStampedTableParser<T extends TimeStamped> {

  37.     /** Interface for converting a table row into time-stamped data.
  38.      * @param <S> the type of time stamped data (i.e. parsed table rows)
  39.      */
  40.     public interface RowConverter<S extends TimeStamped> {

  41.         /** Convert a row.
  42.          * @param rawFields raw row fields, as read from the file
  43.          * @return converted row
  44.          * @exception OrekitException if conversion cannot be performed
  45.          */
  46.         S convert(double[] rawFields) throws OrekitException;
  47.     }

  48.     /** Pattern for fields with real type. */
  49.     private static final String  REAL_TYPE_PATTERN =
  50.             "[-+]?(?:(?:\\p{Digit}+(?:\\.\\p{Digit}*)?)|(?:\\.\\p{Digit}+))(?:[eE][-+]?\\p{Digit}+)?";

  51.     /** Number of columns. */
  52.     private final int columns;

  53.     /** Converter for rows. */
  54.     private final RowConverter<T> converter;

  55.     /** Simple constructor.
  56.      * @param columns number of columns
  57.      * @param converter converter for rows
  58.      */
  59.     public SimpleTimeStampedTableParser(final int columns, final RowConverter<T> converter) {
  60.         this.columns   = columns;
  61.         this.converter = converter;
  62.     }

  63.     /** Parse a stream.
  64.      * @param stream stream containing the table
  65.      * @param name name of the resource file (for error messages only)
  66.      * @return parsed table
  67.      * @exception OrekitException if stream is null or the table cannot be parsed
  68.      */
  69.     public List<T> parse(final InputStream stream, final String name) throws OrekitException {

  70.         if (stream == null) {
  71.             throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, name);
  72.         }

  73.         // regular lines are simply a space separated list of numbers
  74.         final StringBuilder builder = new StringBuilder("^\\p{Space}*");
  75.         for (int i = 0; i < columns; ++i) {
  76.             builder.append("(");
  77.             builder.append(REAL_TYPE_PATTERN);
  78.             builder.append(")");
  79.             builder.append((i < columns - 1) ? "\\p{Space}+" : "\\p{Space}*$");
  80.         }
  81.         final Pattern regularLinePattern = Pattern.compile(builder.toString());

  82.         try {

  83.             // setup the reader
  84.             final BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));

  85.             final List<T> table = new ArrayList<T>();

  86.             for (String line = reader.readLine(); line != null; line = reader.readLine()) {

  87.                 // replace unicode minus sign ('−') by regular hyphen ('-') for parsing
  88.                 // such unicode characters occur in tables that are copy-pasted from PDF files
  89.                 line = line.replace('\u2212', '-');

  90.                 final Matcher regularMatcher = regularLinePattern.matcher(line);
  91.                 if (regularMatcher.matches()) {
  92.                     // we have found a regular data line

  93.                     final double[] rawFields = new double[columns];
  94.                     for (int i = 0; i < columns; ++i) {
  95.                         rawFields[i] = Double.parseDouble(regularMatcher.group(i + 1));
  96.                     }

  97.                     table.add(converter.convert(rawFields));

  98.                 }

  99.             }

  100.             if (table.isEmpty()) {
  101.                 throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, name);
  102.             }

  103.             return table;

  104.         } catch (IOException ioe) {
  105.             throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
  106.         }

  107.     }

  108. }