1 /* $RCSfile$
2  * $Author$
3  * $Date$
4  * $Revision$
5  *
6  * Copyright (C) 2006  The Jmol Development Team
7  *
8  * Contact: jmol-developers@lists.sf.net
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2.1 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  *  02110-1301, USA.
24  */
25 
26 package org.jmol.util;
27 
28 import javajs.util.PT;
29 
30 import javajs.util.BS;
31 
32 public class Parser {
33 
34   /**
35    * parses a "dirty" string for floats. If there are non-float tokens,
36    * they are ignored. A bitset is used to assign values only to specific
37    * atoms in the set, not changing the values of the data array for other atoms.
38    * thus, a data set can be incrementally added to in this way.
39    *
40    *  @param str     the string to parse
41    *  @param bs      the atom positions to assign
42    *  @param data    the (sparce) array to fill
43    * @return  number of floats
44    */
parseStringInfestedFloatArray(String str, BS bs, float[] data)45   public static int parseStringInfestedFloatArray(String str, BS bs, float[] data) {
46     return Parser.parseFloatArrayBsData(PT.getTokens(str), bs, data);
47   }
48 
parseFloatArrayBsData(String[] tokens, BS bs, float[] data)49   public static int parseFloatArrayBsData(String[] tokens, BS bs, float[] data) {
50     int len = data.length;
51     int nTokens = tokens.length;
52     int n = 0;
53     int max = 0;
54     boolean haveBitSet = (bs != null);
55     for (int i = (haveBitSet ? bs.nextSetBit(0) : 0); i >= 0 && i < len && n < nTokens; i = (haveBitSet ? bs.nextSetBit(i + 1) : i + 1)) {
56       float f;
57       while (Float.isNaN(f = PT.parseFloat(tokens[n++]))
58           && n < nTokens) {
59       }
60       if (!Float.isNaN(f))
61         data[(max = i)] = f;
62       if (n == nTokens)
63         break;
64     }
65     return max + 1;
66   }
67 
68   /**
69    * the major lifter here.
70    *
71    * @param str         string containing the data
72    * @param bs          selects specific rows of the data
73    * @param fieldMatch  a free-format field pointer, or a column pointer
74    * @param fieldMatchColumnCount specifies a column count -- not free-format
75    * @param matchData   an array of data to match (atom numbers)
76    * @param field       a free-format field pointer, or a column pointer
77    * @param fieldColumnCount specifies a column count -- not free-format
78    * @param data        float array to modify or null if size unknown
79    * @param firstLine   first line to parse (1 indicates all)
80    * @return            data
81    */
parseFloatArrayFromMatchAndField( String str, BS bs, int fieldMatch, int fieldMatchColumnCount, int[] matchData, int field, int fieldColumnCount, float[] data, int firstLine)82   public static float[] parseFloatArrayFromMatchAndField(
83                                                          String str,
84                                                          BS bs,
85                                                          int fieldMatch,
86                                                          int fieldMatchColumnCount,
87                                                          int[] matchData,
88                                                          int field,
89                                                          int fieldColumnCount,
90                                                          float[] data, int firstLine) {
91     float f;
92     int i = -1;
93     boolean isMatch = (matchData != null);
94     int[] lines = markLines(str, (str.indexOf('\n') >= 0 ? '\n' : ';'));
95     int iLine = (firstLine <= 1 || firstLine >= lines.length ? 0 : firstLine - 1);
96     int pt = (iLine == 0 ? 0 : lines[iLine - 1]);
97     int nLines = lines.length;
98     if (data == null)
99       data = new float[nLines - iLine];
100     int len = data.length;
101     int minLen = (fieldColumnCount <= 0 ? Math.max(field, fieldMatch) : Math
102         .max(field + fieldColumnCount, fieldMatch + fieldMatchColumnCount) - 1);
103     boolean haveBitSet = (bs != null);
104     for (; iLine < nLines; iLine++) {
105       String line = str.substring(pt, lines[iLine]).trim();
106       pt = lines[iLine];
107       String[] tokens = (fieldColumnCount <= 0 ? PT.getTokens(line) : null);
108       // check for inappropriate data -- line too short or too few tokens or NaN for data
109       // and parse data
110       if (fieldColumnCount <= 0) {
111         if (tokens.length < minLen
112             || Float.isNaN(f = PT.parseFloat(tokens[field - 1])))
113           continue;
114       } else {
115         if (line.length() < minLen
116             || Float.isNaN(f = PT.parseFloat(line.substring(field - 1, field
117                 + fieldColumnCount - 1))))
118           continue;
119       }
120       int iData;
121       if (isMatch) {
122         iData = PT.parseInt(tokens == null ? line.substring(fieldMatch - 1,
123             fieldMatch + fieldMatchColumnCount - 1) : tokens[fieldMatch - 1]);
124         // in the fieldMatch column we have an integer pointing into matchData
125         // we replace that number then with the corresponding number in matchData
126         if (iData == Integer.MIN_VALUE || iData < 0 || iData >= len
127             || (iData = matchData[iData]) < 0)
128           continue;
129         // and we set bs to indicate we are updating that value
130         if (haveBitSet)
131           bs.set(iData);
132       } else {
133         // no match data
134         // bs here indicates the specific data elements that need filling
135         if (haveBitSet)
136           i = bs.nextSetBit(i + 1);
137         else
138           i++;
139         if (i < 0 || i >= len)
140           return data;
141         iData = i;
142       }
143       data[iData] = f;
144       //System.out.println("data[" + iData + "] = " + data[iData]);
145     }
146     return data;
147   }
148 
fixDataString(String str)149   public static String fixDataString(String str) {
150     str = str.replace(';', str.indexOf('\n') < 0 ? '\n' : ' ');
151     str = PT.trim(str, "\n \t");
152     str = PT.rep(str, "\n ", "\n");
153     str = PT.rep(str, "\n\n", "\n");
154     return str;
155   }
156 
markLines(String data, char eol)157   public static int[] markLines(String data, char eol) {
158     int nLines = 0;
159     for (int i = data.length(); --i >=0;)
160       if (data.charAt(i) == eol)
161         nLines++;
162     int[] lines = new int[nLines + 1];
163     nLines = 0;
164     int pt = 0;
165     while ((pt = data.indexOf(eol, pt)) >= 0)
166       lines[nLines++] = ++pt;
167     lines[nLines] = data.length();
168     return lines;
169   }
170 
171 
172 }
173