All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.nc2.util.TableParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */

package ucar.nc2.util;

import ucar.nc2.constants.CDM;
import ucar.unidata.util.StringUtil2;

import java.io.*;
import java.util.*;
import java.net.URL;

/**
 * Utility class to read and parse a fixed length table.
 * Each line of the table becomes a "Record". Each Record has a set of Fields described by the format string.
 * 

*

 * List recs = TableParser.readTable(is, "3,15,46,54,60d,67d,73d", 50000);
 * for (TableParser.Record record : recs) {
 * Station s = new Station();
 * s.id = "K" + record.get(0);
 * s.name = record.get(2) + " " + record.get(3);
 * s.lat = (Double) record.get(4) * .01;
 * s.lon = (Double) record.get(5) * .01;
 * s.elev = (Double) record.get(6);
 * 

* stationTableHash.put(s.id, s); * if (showStations) System.out.println(" station= " + s); * } *

* Example Table: * TLX 000001 OKLAHOMA_CITY/Norman OK US 3532 -9727 370 0 NWS * AMA 000313 AMARILLO/Amarillo TX US 3523 -10170 1093 0 NWS * HGX 000378 HOUSTON/GALVESTON/Dickinson TX US 2947 -9507 5 0 NWS * MLB 000302 MELBOURNE/Melbourne FL US 2810 -8065 11 0 NWS *

* format: * "3,15,54,60d,67d,73d" *

* grammer: * format = {field,} * field = endPos type * endPos = ending pos in the line, 0 based, exclusive, ie [start, end) * type = i=integer, d=double, L=long else String * field[0] goes from [0, endPos[0]) * field[i] goes from [endPos[i-1] to endPos[i]) *

*

* * @author caron */ /* ClassLoader cl = Level2VolumeScan.class.getClassLoader(); InputStream is = cl.getResourceAsStream("resources/nj22/tables/nexrad.tbl"); List recs = TableParser.readTable(is, "3,15,46, 54,60d,67d,73d", 50000); for (TableParser.Record record : recs) { Station s = new Station(); s.id = "K" + record.get(0); s.name = record.get(2) + " " + record.get(3); s.lat = (Double) record.get(4) * .01; s.lon = (Double) record.get(5) * .01; s.elev = (Double) record.get(6); stationTableHash.put(s.id, s); if (showStations) System.out.println(" station= " + s); } 1 2 3 4 5 6 7 8 9 10 11 12 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ public class TableParser { static private final boolean debug = false; /** * Reads a URL or file in as a table. * * @param urlString starts with http, read URL contenets, else read file. * @param format describe format of each line. * @param maxLines maximum number of lines to parse, set to < 0 to read all * @return List of TableParser.Record * @throws IOException on read error * @throws NumberFormatException on parse number error * @see #readTable(InputStream ios, String format, int maxLines) */ static public List readTable(String urlString, String format, int maxLines) throws IOException, NumberFormatException { InputStream ios; if (urlString.startsWith("http:")) { URL url = new URL(urlString); ios = url.openStream(); } else { ios = new FileInputStream(urlString); } return readTable(ios, format, maxLines); } /** * Reads an input stream, containing lines of ascii in fixed width format. * Breaks each line into a set of Fields (space or comma delimited) which may be String, integer or double. * * @param ios the input stream, will be closed * @param format describe format of each line. * @param maxLines maximum number of lines to parse, set to < 0 to read all * @return List of TableParser.Record * @throws IOException on read error * @throws NumberFormatException on parse number error */ static public List readTable(InputStream ios, String format, int maxLines) throws IOException, NumberFormatException { List result; try { TableParser parser = new TableParser(format); result = parser.readAllRecords(ios, maxLines); } finally { ios.close(); } return result; } ///////////////////////////////////////////////////////////////////////////////////////////////// private List fields = new ArrayList<>(); public TableParser(String format) throws IOException, NumberFormatException { int start = 0; StringTokenizer stoker = new StringTokenizer(format, " ,"); while (stoker.hasMoreTokens()) { String tok = stoker.nextToken(); // see what type Class type = String.class; char last = tok.charAt(tok.length() - 1); if (last == 'i') type = int.class; if (last == 'd') type = double.class; if (last == 'L') type = long.class; if (type != String.class) tok = tok.substring(0, tok.length() - 1); int end = Integer.parseInt(tok); fields.add(new Field(start, end, type)); start = end; } } private String comment = "#"; public void setComment(String comment) { this.comment = comment; } public List readAllRecords(InputStream ios, int maxLines) throws IOException, NumberFormatException { List records = new ArrayList<>(); BufferedReader dataIS = new BufferedReader(new InputStreamReader(ios, CDM.utf8Charset)); int count = 0; while ((maxLines < 0) || (count < maxLines)) { String line = dataIS.readLine(); if (line == null) break; if (line.startsWith(comment)) continue; if (line.trim().length() == 0) continue; if (debug) System.out.printf("%s%n", line); Record r = Record.make(line, fields); if (r != null) records.add(r); count++; } return records; } public Field getField(int fldno) { return fields.get(fldno); } public int getNumberOfFields() { return fields.size(); } /** * Describes one field in the record. */ public static class Field { int start, end; Class type; boolean hasScale = false; float scale; Field(int start, int end, Class type) { this.start = start; this.end = end; this.type = type; } protected Field() {} public Object parse(String line) throws NumberFormatException { return parse(line, this.start, this.end); } public Object parse(String line, int offset) throws NumberFormatException { return parse(line, this.start+offset, this.end+offset); } protected Object parse(String line, int start, int end) throws NumberFormatException { String svalue; if (start >= line.length()) svalue = ""; else if (end >= line.length()) svalue = line.substring(start); else svalue = line.substring(start, end); //System.out.printf(" [%d,%d) = %s %n",start, end, svalue); if (type == String.class) return svalue; try { svalue = StringUtil2.remove(svalue, ' '); boolean isBlank = (svalue.trim().length() == 0); if (type == double.class) return isBlank ? 0.0 : new Double(svalue); if (type == int.class) { Integer result = isBlank ? 0 : new Integer(svalue); if (hasScale) return result * scale; else return result; } if (type == long.class) return isBlank ? 0L : new Long(svalue); } catch (NumberFormatException e) { System.out.printf(" [%d,%d) = <%s> %n", start, end, svalue); throw e; } return null; } public void setScale(float scale) { this.scale = scale; hasScale = true; } } public DerivedField addDerivedField(Field from, Transform transform, Class type ) { DerivedField fld = new DerivedField(from, transform, type); fields.add(fld); return fld; } public static class DerivedField extends Field { Field from; Transform transform; DerivedField(Field from, Transform transform, Class type) { this.from = from; this.transform = transform; this.type = type; } protected Object parse(String line, int start, int end) throws NumberFormatException { Object org = from.parse(line); return transform.derive(org); } } public interface Transform { Object derive(Object org); } /** * A set of values for one line. */ static public class Record { List values = new ArrayList<>(); static Record make(String line, List fields) { try { Record r = new Record(); for (Object field : fields) { Field f = (Field) field; r.values.add(f.parse(line)); } return r; } catch (NumberFormatException e) { System.out.printf("Bad line=%s %n", line); return null; } } public int nfields() { return values.size(); } /** * Get the kth value of this record. Will be a String, Double, or Integer. * * @param k which one * @return object */ public Object get(int k) { return values.get(k); } public void toString(Formatter f) { for (Object s : values) f.format(" %s,", s.toString()); f.format("%n"); } } }