KeyValue.java
/* Copyright 2002-2020 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.files.ccsds;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
/** Holder for key-value pair.
* <p>
* The syntax for key-value lines in CCSDS files is:
* </p>
* <pre>
* KEY = value [unit]
* </pre>
* <p>
* The "[unit]" part (with the square brackets included) is optional.
* The COMMENT keyword is an exception and does not have an '=' but directly
* the value as free form text. The META_START, META_STOP, COVARIANCE_START
* and COVARIANCE_STOP keywords are other exception and do not have anything
* else following them on the line.
* </p>
* @author Luc Maisonobe
* @since 6.1
*/
class KeyValue {
/** Regular expression for spaces. */
private static final Pattern SPACE = Pattern.compile("\\p{Space}+");
/** Regular expression for splitting lines. */
private static final Pattern PATTERN =
Pattern.compile("\\p{Space}*([A-Z][A-Z_0-9]*)\\p{Space}*=?\\p{Space}*(.*?)\\p{Space}*(?:\\[.*\\])?\\p{Space}*");
/** Regular expression for user defined keywords. */
private static final Pattern USER_DEFINED_KEYWORDS =
Pattern.compile("USER_DEFINED_[A-Z][A-Z_]*");
/** Line from which pair is extracted. */
private final String line;
/** Number of the line from which pair is extracted. */
private final int lineNumber;
/** Name of the file. */
private final String fileName;
/** Keyword enum corresponding to parsed key. */
private final Keyword keyword;
/** Key part of the pair. */
private final String key;
/** Value part of the line. */
private final String value;
/** Build a pair by splitting a key-value line.
* <p>
* The splitting is very basic and only extracts words using a regular
* expression ignoring the '=' sign and the optional unit. No attempt
* is made to recognize the special keywords. The key and value parts
* may be empty if not matched, and the keyword may be null.
* </p>
* <p> The value part may be upper case or lower case. This constructor
* converts all lower case values to upper case.
* @param line to split
* @param lineNumber number of the line in the CCSDS data message
* @param fileName name of the file
*/
KeyValue(final String line, final int lineNumber, final String fileName) {
this.line = line;
this.lineNumber = lineNumber;
this.fileName = fileName;
final Matcher matcher = PATTERN.matcher(line);
if (matcher.matches()) {
key = matcher.group(1);
final String rawValue = matcher.group(2);
Keyword recognized;
try {
recognized = Keyword.valueOf(key);
} catch (IllegalArgumentException iae) {
if (USER_DEFINED_KEYWORDS.matcher(key).matches()) {
recognized = Keyword.USER_DEFINED_X;
} else {
recognized = null;
}
}
keyword = recognized;
if (recognized == Keyword.COMMENT) {
value = rawValue;
} else {
value = SPACE.matcher(rawValue.toUpperCase(Locale.US).replace('_', ' '))
.replaceAll(" ");
}
} else {
key = "";
value = key;
keyword = null;
}
}
/** Build a pair by giving the input arguments.
* This is essentially used while parsing XML files.
* It is made to be allow the use of the class KeyValue for both Keyvalue and XML file formats.
* Thus common functions can be used for the parsing.
* <p>
* The splitting is very basic and only extracts words using a regular
* expression ignoring the '=' sign and the optional unit. No attempt
* is made to recognize the special keywords. The key and value parts
* may be empty if not matched, and the keyword may be null.
* </p>
* <p> The value part may be upper case or lower case. This constructor
* converts all lower case values to upper case.
* @param keyword the keyword
* @param value the value attached to the keyword
* @param line the line where the keyword was found
* @param lineNumber number of the line in the CCSDS data message
* @param fileName name of the file
*/
KeyValue(final Keyword keyword, final String value,
final String line, final int lineNumber,
final String fileName) {
this.keyword = keyword;
this.key = keyword.name();
this.value = value;
this.lineNumber = lineNumber;
this.line = line;
this.fileName = fileName;
}
/** Keyword corresponding to the parsed key.
* @return keyword corresponding to the parsed key
* (null if not recognized)
*/
public Keyword getKeyword() {
return keyword;
}
/** Get the key.
* @return key
*/
public String getKey() {
return key;
}
/** Get the value.
* @return value
*/
public String getValue() {
return value;
}
/** Get the value as a double number.
* @return value
*/
public double getDoubleValue() {
try {
return Double.parseDouble(value);
} catch (NumberFormatException nfe) {
throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
lineNumber, fileName, line);
}
}
/** Get the value as an integer number.
* @return value
*/
public int getIntegerValue() {
try {
return Integer.parseInt(value);
} catch (NumberFormatException nfe) {
throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
lineNumber, fileName, line);
}
}
}