2317 |
24 May 06 |
nicklas |
1 |
/** |
2317 |
24 May 06 |
nicklas |
$Id$ |
2317 |
24 May 06 |
nicklas |
3 |
|
3675 |
16 Aug 07 |
jari |
Copyright (C) 2006, 2007 Nicklas Nordborg |
2317 |
24 May 06 |
nicklas |
5 |
|
2317 |
24 May 06 |
nicklas |
This file is part of BASE - BioArray Software Environment. |
2317 |
24 May 06 |
nicklas |
Available at http://base.thep.lu.se/ |
2317 |
24 May 06 |
nicklas |
8 |
|
2317 |
24 May 06 |
nicklas |
BASE is free software; you can redistribute it and/or |
2317 |
24 May 06 |
nicklas |
modify it under the terms of the GNU General Public License |
4479 |
05 Sep 08 |
jari |
as published by the Free Software Foundation; either version 3 |
2317 |
24 May 06 |
nicklas |
of the License, or (at your option) any later version. |
2317 |
24 May 06 |
nicklas |
13 |
|
2317 |
24 May 06 |
nicklas |
BASE is distributed in the hope that it will be useful, |
2317 |
24 May 06 |
nicklas |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
2317 |
24 May 06 |
nicklas |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2317 |
24 May 06 |
nicklas |
GNU General Public License for more details. |
2317 |
24 May 06 |
nicklas |
18 |
|
2317 |
24 May 06 |
nicklas |
You should have received a copy of the GNU General Public License |
4515 |
11 Sep 08 |
jari |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
2317 |
24 May 06 |
nicklas |
21 |
*/ |
2317 |
24 May 06 |
nicklas |
22 |
package net.sf.basedb.util.parser; |
2317 |
24 May 06 |
nicklas |
23 |
|
3023 |
12 Dec 06 |
nicklas |
24 |
import java.text.NumberFormat; |
3023 |
12 Dec 06 |
nicklas |
25 |
import java.text.ParsePosition; |
7667 |
21 Mar 19 |
nicklas |
26 |
import java.util.Date; |
3911 |
06 Nov 07 |
nicklas |
27 |
import java.util.LinkedHashMap; |
2655 |
22 Sep 06 |
nicklas |
28 |
import java.util.List; |
2317 |
24 May 06 |
nicklas |
29 |
import java.util.Map; |
2317 |
24 May 06 |
nicklas |
30 |
import java.util.Stack; |
3911 |
06 Nov 07 |
nicklas |
31 |
import java.util.regex.Pattern; |
3911 |
06 Nov 07 |
nicklas |
32 |
import java.util.regex.PatternSyntaxException; |
2317 |
24 May 06 |
nicklas |
33 |
|
2317 |
24 May 06 |
nicklas |
34 |
import org.nfunk.jep.ParseException; |
2317 |
24 May 06 |
nicklas |
35 |
|
2317 |
24 May 06 |
nicklas |
36 |
import net.sf.basedb.core.BaseException; |
7664 |
20 Mar 19 |
nicklas |
37 |
import net.sf.basedb.core.Type; |
7667 |
21 Mar 19 |
nicklas |
38 |
import net.sf.basedb.util.formatter.Formatter; |
2317 |
24 May 06 |
nicklas |
39 |
import net.sf.basedb.util.jep.JepFunction; |
2317 |
24 May 06 |
nicklas |
40 |
|
2317 |
24 May 06 |
nicklas |
41 |
/** |
2317 |
24 May 06 |
nicklas |
Adds a <code>col()</code> function to Jep. The col function is used with the |
2317 |
24 May 06 |
nicklas |
{@link FlatFileParser} to get the value of a data column. The argument to |
2317 |
24 May 06 |
nicklas |
the col function is either the column name or index (0-based). Use the |
2317 |
24 May 06 |
nicklas |
{@link FlatFileParser#getMapper(String)} with an argument starting with an equal |
2317 |
24 May 06 |
nicklas |
sign to create a mapper that uses Jep. |
2317 |
24 May 06 |
nicklas |
<pre class="code"> |
2317 |
24 May 06 |
nicklas |
FlatFileParser ffp = ... |
3618 |
01 Aug 07 |
nicklas |
Mapper diameterMapper = ffp.getMapper("=col('Radius') * 2"); |
2317 |
24 May 06 |
nicklas |
while (ffp.hasMoreData()) |
2317 |
24 May 06 |
nicklas |
51 |
{ |
2317 |
24 May 06 |
nicklas |
Data data = ffp.nextData(); |
2317 |
24 May 06 |
nicklas |
float diameter = diameterMapper.getFloat(data); |
2317 |
24 May 06 |
nicklas |
54 |
} |
2317 |
24 May 06 |
nicklas |
</pre> |
2317 |
24 May 06 |
nicklas |
56 |
|
2317 |
24 May 06 |
nicklas |
@author nicklas |
2317 |
24 May 06 |
nicklas |
@version 2.0 |
2317 |
24 May 06 |
nicklas |
@base.modified $Date$ |
2317 |
24 May 06 |
nicklas |
60 |
*/ |
2317 |
24 May 06 |
nicklas |
61 |
public class ColFunction |
2317 |
24 May 06 |
nicklas |
62 |
implements JepFunction |
2317 |
24 May 06 |
nicklas |
63 |
{ |
2317 |
24 May 06 |
nicklas |
64 |
|
2317 |
24 May 06 |
nicklas |
65 |
private final Map<String, Integer> columnHeaders; |
3023 |
12 Dec 06 |
nicklas |
66 |
private final NumberFormat numberFormat; |
7667 |
21 Mar 19 |
nicklas |
67 |
private final Formatter<Date> dateFormat; |
3023 |
12 Dec 06 |
nicklas |
68 |
private final ParsePosition pos; |
2317 |
24 May 06 |
nicklas |
69 |
private FlatFileParser.Data data; |
7664 |
20 Mar 19 |
nicklas |
70 |
private Type nextValueType; |
4104 |
28 Jan 08 |
nicklas |
71 |
private boolean ignoreNonExistingColumns = false; |
2317 |
24 May 06 |
nicklas |
72 |
|
3023 |
12 Dec 06 |
nicklas |
73 |
public ColFunction(Map<String, Integer> columnHeaders, NumberFormat numberFormat) |
2317 |
24 May 06 |
nicklas |
74 |
{ |
7667 |
21 Mar 19 |
nicklas |
75 |
this(columnHeaders, numberFormat, null); |
7667 |
21 Mar 19 |
nicklas |
76 |
} |
7667 |
21 Mar 19 |
nicklas |
77 |
|
7667 |
21 Mar 19 |
nicklas |
78 |
/** |
7667 |
21 Mar 19 |
nicklas |
@since 3.15 |
7667 |
21 Mar 19 |
nicklas |
80 |
*/ |
7667 |
21 Mar 19 |
nicklas |
81 |
public ColFunction(Map<String, Integer> columnHeaders, NumberFormat numberFormat, Formatter<Date> dateFormat) |
7667 |
21 Mar 19 |
nicklas |
82 |
{ |
2317 |
24 May 06 |
nicklas |
83 |
this.columnHeaders = columnHeaders; |
3023 |
12 Dec 06 |
nicklas |
84 |
this.numberFormat = numberFormat; |
7667 |
21 Mar 19 |
nicklas |
85 |
this.dateFormat = dateFormat; |
3023 |
12 Dec 06 |
nicklas |
86 |
this.pos = new ParsePosition(0); |
2317 |
24 May 06 |
nicklas |
87 |
} |
7667 |
21 Mar 19 |
nicklas |
88 |
|
3023 |
12 Dec 06 |
nicklas |
89 |
public ColFunction(List<String> columnHeaders, NumberFormat numberFormat) |
2655 |
22 Sep 06 |
nicklas |
90 |
{ |
7667 |
21 Mar 19 |
nicklas |
91 |
this(columnHeaders, numberFormat, null); |
7667 |
21 Mar 19 |
nicklas |
92 |
} |
7667 |
21 Mar 19 |
nicklas |
93 |
|
7667 |
21 Mar 19 |
nicklas |
94 |
/** |
7667 |
21 Mar 19 |
nicklas |
@since 3.15 |
7667 |
21 Mar 19 |
nicklas |
96 |
*/ |
7667 |
21 Mar 19 |
nicklas |
97 |
public ColFunction(List<String> columnHeaders, NumberFormat numberFormat, Formatter<Date> dateFormat) |
7667 |
21 Mar 19 |
nicklas |
98 |
{ |
3023 |
12 Dec 06 |
nicklas |
99 |
this.numberFormat = numberFormat; |
7667 |
21 Mar 19 |
nicklas |
100 |
this.dateFormat = dateFormat; |
3023 |
12 Dec 06 |
nicklas |
101 |
this.pos = new ParsePosition(0); |
3911 |
06 Nov 07 |
nicklas |
102 |
this.columnHeaders = new LinkedHashMap<String, Integer>(columnHeaders.size()); |
2655 |
22 Sep 06 |
nicklas |
103 |
int index = 0; |
2655 |
22 Sep 06 |
nicklas |
104 |
for (String header : columnHeaders) |
2655 |
22 Sep 06 |
nicklas |
105 |
{ |
2655 |
22 Sep 06 |
nicklas |
106 |
this.columnHeaders.put(header, index); |
2655 |
22 Sep 06 |
nicklas |
107 |
index++; |
2655 |
22 Sep 06 |
nicklas |
108 |
} |
2655 |
22 Sep 06 |
nicklas |
109 |
} |
2655 |
22 Sep 06 |
nicklas |
110 |
|
2317 |
24 May 06 |
nicklas |
111 |
/* |
2317 |
24 May 06 |
nicklas |
From the JepFunction interface |
2317 |
24 May 06 |
nicklas |
113 |
------------------------------------------- |
2317 |
24 May 06 |
nicklas |
114 |
*/ |
2317 |
24 May 06 |
nicklas |
115 |
/** |
2317 |
24 May 06 |
nicklas |
@return The string "col" |
2317 |
24 May 06 |
nicklas |
117 |
*/ |
6127 |
14 Sep 12 |
nicklas |
118 |
@Override |
2317 |
24 May 06 |
nicklas |
119 |
public String getFunctionName() |
2317 |
24 May 06 |
nicklas |
120 |
{ |
2317 |
24 May 06 |
nicklas |
121 |
return "col"; |
2317 |
24 May 06 |
nicklas |
122 |
} |
2317 |
24 May 06 |
nicklas |
123 |
// ------------------------------------------- |
2317 |
24 May 06 |
nicklas |
124 |
/* |
2317 |
24 May 06 |
nicklas |
From the PostfixMathCommandI interface |
2317 |
24 May 06 |
nicklas |
126 |
------------------------------------------- |
2317 |
24 May 06 |
nicklas |
127 |
*/ |
2317 |
24 May 06 |
nicklas |
128 |
/** |
2317 |
24 May 06 |
nicklas |
@return Always 1 |
2317 |
24 May 06 |
nicklas |
130 |
*/ |
6127 |
14 Sep 12 |
nicklas |
131 |
@Override |
2317 |
24 May 06 |
nicklas |
132 |
public int getNumberOfParameters() |
2317 |
24 May 06 |
nicklas |
133 |
{ |
2317 |
24 May 06 |
nicklas |
134 |
return 1; |
2317 |
24 May 06 |
nicklas |
135 |
} |
6127 |
14 Sep 12 |
nicklas |
136 |
@Override |
2317 |
24 May 06 |
nicklas |
137 |
public void setCurNumberOfParameters(int n) |
2317 |
24 May 06 |
nicklas |
138 |
{} |
6127 |
14 Sep 12 |
nicklas |
139 |
@Override |
2474 |
31 Jul 06 |
nicklas |
140 |
public boolean checkNumberOfParameters(int n) |
2474 |
31 Jul 06 |
nicklas |
141 |
{ |
2474 |
31 Jul 06 |
nicklas |
142 |
return n == 1; |
2474 |
31 Jul 06 |
nicklas |
143 |
} |
6127 |
14 Sep 12 |
nicklas |
144 |
@Override |
6875 |
20 Apr 15 |
nicklas |
145 |
@SuppressWarnings({"unchecked", "rawtypes"}) |
2317 |
24 May 06 |
nicklas |
146 |
public void run(Stack stack) |
2317 |
24 May 06 |
nicklas |
147 |
throws ParseException |
2317 |
24 May 06 |
nicklas |
148 |
{ |
2317 |
24 May 06 |
nicklas |
149 |
if (stack == null || stack.empty()) |
2317 |
24 May 06 |
nicklas |
150 |
{ |
2317 |
24 May 06 |
nicklas |
151 |
throw new ParseException("Stack is empty"); |
2317 |
24 May 06 |
nicklas |
152 |
} |
2317 |
24 May 06 |
nicklas |
153 |
Object argument = stack.pop(); |
7664 |
20 Mar 19 |
nicklas |
154 |
Integer column = null; |
2317 |
24 May 06 |
nicklas |
155 |
if (argument instanceof Number) |
2317 |
24 May 06 |
nicklas |
156 |
{ |
7664 |
20 Mar 19 |
nicklas |
157 |
column = ((Number)argument).intValue(); |
2317 |
24 May 06 |
nicklas |
158 |
} |
2317 |
24 May 06 |
nicklas |
159 |
else if (argument instanceof String) |
2317 |
24 May 06 |
nicklas |
160 |
{ |
2317 |
24 May 06 |
nicklas |
161 |
String colName = (String)argument; |
7664 |
20 Mar 19 |
nicklas |
162 |
column = columnHeaders.get(colName); |
3911 |
06 Nov 07 |
nicklas |
163 |
if (column == null) column = findColumn(colName); |
3911 |
06 Nov 07 |
nicklas |
164 |
if (column == null) |
2317 |
24 May 06 |
nicklas |
165 |
{ |
4104 |
28 Jan 08 |
nicklas |
166 |
if (!ignoreNonExistingColumns) |
4104 |
28 Jan 08 |
nicklas |
167 |
{ |
4104 |
28 Jan 08 |
nicklas |
168 |
throw new BaseException("Column '" + colName + "' not found in column headers."); |
4104 |
28 Jan 08 |
nicklas |
169 |
} |
2317 |
24 May 06 |
nicklas |
170 |
} |
2317 |
24 May 06 |
nicklas |
171 |
} |
2317 |
24 May 06 |
nicklas |
172 |
else |
2317 |
24 May 06 |
nicklas |
173 |
{ |
2317 |
24 May 06 |
nicklas |
174 |
throw new ParseException("Invalid parameter type: " + argument + "; expected number"); |
2317 |
24 May 06 |
nicklas |
175 |
} |
7664 |
20 Mar 19 |
nicklas |
176 |
|
7664 |
20 Mar 19 |
nicklas |
177 |
Object value = null; |
7665 |
20 Mar 19 |
nicklas |
178 |
if (column != null && column < data.columns()) |
2317 |
24 May 06 |
nicklas |
179 |
{ |
7672 |
21 Mar 19 |
nicklas |
180 |
try |
3023 |
12 Dec 06 |
nicklas |
181 |
{ |
7672 |
21 Mar 19 |
nicklas |
182 |
value = data.getDouble(column, numberFormat, false); |
3023 |
12 Dec 06 |
nicklas |
183 |
} |
7672 |
21 Mar 19 |
nicklas |
184 |
catch (RuntimeException ex) |
7667 |
21 Mar 19 |
nicklas |
185 |
{ |
7672 |
21 Mar 19 |
nicklas |
186 |
if (nextValueType.isTemporal()) |
7672 |
21 Mar 19 |
nicklas |
187 |
{ |
7672 |
21 Mar 19 |
nicklas |
188 |
value = data.getDate(column, dateFormat, true); |
7672 |
21 Mar 19 |
nicklas |
189 |
} |
7672 |
21 Mar 19 |
nicklas |
190 |
else |
7672 |
21 Mar 19 |
nicklas |
191 |
{ |
7672 |
21 Mar 19 |
nicklas |
192 |
value = data.getString(column); |
7672 |
21 Mar 19 |
nicklas |
193 |
} |
7667 |
21 Mar 19 |
nicklas |
194 |
} |
2317 |
24 May 06 |
nicklas |
195 |
} |
7664 |
20 Mar 19 |
nicklas |
196 |
stack.push(value); |
2317 |
24 May 06 |
nicklas |
197 |
} |
2317 |
24 May 06 |
nicklas |
198 |
// ------------------------------------------- |
2317 |
24 May 06 |
nicklas |
199 |
|
4104 |
28 Jan 08 |
nicklas |
200 |
/** |
4104 |
28 Jan 08 |
nicklas |
Set to TRUE to ignore non-existing columns. Set to FALSE to |
4104 |
28 Jan 08 |
nicklas |
throw an exception (default). |
4104 |
28 Jan 08 |
nicklas |
@since 2.6 |
4104 |
28 Jan 08 |
nicklas |
204 |
*/ |
4104 |
28 Jan 08 |
nicklas |
205 |
public void setIgnoreNonExistingColumns(boolean ignoreNonExistingColumns) |
4104 |
28 Jan 08 |
nicklas |
206 |
{ |
4104 |
28 Jan 08 |
nicklas |
207 |
this.ignoreNonExistingColumns = ignoreNonExistingColumns; |
4104 |
28 Jan 08 |
nicklas |
208 |
} |
4104 |
28 Jan 08 |
nicklas |
209 |
|
7664 |
20 Mar 19 |
nicklas |
210 |
public void setData(FlatFileParser.Data data, Type valueType) |
2317 |
24 May 06 |
nicklas |
211 |
{ |
2317 |
24 May 06 |
nicklas |
212 |
this.data = data; |
7664 |
20 Mar 19 |
nicklas |
213 |
this.nextValueType = valueType; |
2317 |
24 May 06 |
nicklas |
214 |
} |
3911 |
06 Nov 07 |
nicklas |
215 |
|
3911 |
06 Nov 07 |
nicklas |
216 |
/** |
3911 |
06 Nov 07 |
nicklas |
Find column index by checking each column header against a |
3911 |
06 Nov 07 |
nicklas |
regular expression. The first match found is returned. The |
6898 |
12 May 15 |
nicklas |
map is updated with a new regex -> index entry. |
3911 |
06 Nov 07 |
nicklas |
@return The column index or null if no column is found or if the |
3911 |
06 Nov 07 |
nicklas |
string is not a valid regular expression |
3911 |
06 Nov 07 |
nicklas |
222 |
*/ |
3911 |
06 Nov 07 |
nicklas |
223 |
private Integer findColumn(String regex) |
3911 |
06 Nov 07 |
nicklas |
224 |
{ |
3911 |
06 Nov 07 |
nicklas |
225 |
try |
3911 |
06 Nov 07 |
nicklas |
226 |
{ |
3911 |
06 Nov 07 |
nicklas |
227 |
Pattern p = Pattern.compile(regex); |
3911 |
06 Nov 07 |
nicklas |
228 |
Integer index = null; |
3911 |
06 Nov 07 |
nicklas |
229 |
for (Map.Entry<String, Integer> entry : columnHeaders.entrySet()) |
3911 |
06 Nov 07 |
nicklas |
230 |
{ |
3911 |
06 Nov 07 |
nicklas |
231 |
String column = entry.getKey(); |
3911 |
06 Nov 07 |
nicklas |
232 |
if (p.matcher(column).matches()) |
3911 |
06 Nov 07 |
nicklas |
233 |
{ |
3911 |
06 Nov 07 |
nicklas |
234 |
index = entry.getValue(); |
3911 |
06 Nov 07 |
nicklas |
235 |
break; |
3911 |
06 Nov 07 |
nicklas |
236 |
} |
3911 |
06 Nov 07 |
nicklas |
237 |
} |
3911 |
06 Nov 07 |
nicklas |
238 |
if (index != null) columnHeaders.put(regex, index); |
3911 |
06 Nov 07 |
nicklas |
239 |
return index; |
3911 |
06 Nov 07 |
nicklas |
240 |
} |
3911 |
06 Nov 07 |
nicklas |
241 |
catch (PatternSyntaxException ex) |
3911 |
06 Nov 07 |
nicklas |
242 |
{ |
3911 |
06 Nov 07 |
nicklas |
243 |
return null; |
3911 |
06 Nov 07 |
nicklas |
244 |
} |
3911 |
06 Nov 07 |
nicklas |
245 |
} |
2317 |
24 May 06 |
nicklas |
246 |
|
2317 |
24 May 06 |
nicklas |
247 |
} |