001 package net.sf.cpsolver.ifs.util;
002
003 import java.io.BufferedReader;
004 import java.io.File;
005 import java.io.FileReader;
006 import java.io.FileWriter;
007 import java.io.IOException;
008 import java.io.PrintWriter;
009 import java.io.Serializable;
010 import java.util.Calendar;
011 import java.util.Collection;
012 import java.util.Date;
013 import java.util.Enumeration;
014 import java.util.Hashtable;
015 import java.util.Locale;
016 import java.util.Vector;
017
018 /** Support for CSV (comma separated) text files.
019 *
020 * @version
021 * IFS 1.1 (Iterative Forward Search)<br>
022 * Copyright (C) 2006 Tomáš Müller<br>
023 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
024 * Lazenska 391, 76314 Zlin, Czech Republic<br>
025 * <br>
026 * This library is free software; you can redistribute it and/or
027 * modify it under the terms of the GNU Lesser General Public
028 * License as published by the Free Software Foundation; either
029 * version 2.1 of the License, or (at your option) any later version.
030 * <br><br>
031 * This library is distributed in the hope that it will be useful,
032 * but WITHOUT ANY WARRANTY; without even the implied warranty of
033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
034 * Lesser General Public License for more details.
035 * <br><br>
036 * You should have received a copy of the GNU Lesser General Public
037 * License along with this library; if not, write to the Free Software
038 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
039 */
040
041 public class CSVFile implements Serializable {
042 private static final long serialVersionUID = 1L;
043 Hashtable iHeaderMap = null;
044 CSVLine iHeader = null;
045 Vector iLines = null;
046 String iSeparator = ",";
047 String iQuotationMark = "\"";
048
049 public CSVFile() {}
050
051 public CSVFile(File file) throws IOException {
052 load(file);
053 }
054
055 public CSVFile(File file, String separator) throws IOException {
056 setSeparator(separator);
057 load(file);
058 }
059
060 public CSVFile(File file, String separator, String quotationMark) throws IOException {
061 setSeparator(separator);
062 setQuotationMark(quotationMark);
063 load(file);
064 }
065
066 public void setSeparator(String separator) { iSeparator = separator; }
067 public String getSeparator() { return iSeparator; }
068 public void setQuotationMark(String quotationMark) { iQuotationMark = quotationMark; }
069 public String getQuotationMark() { return iQuotationMark; }
070
071 public void load(File file) throws IOException {
072 BufferedReader reader = null;
073 try {
074 reader = new BufferedReader(new FileReader(file));
075 iHeader = new CSVLine(reader.readLine()); //read header
076 iHeaderMap = new Hashtable();
077 iLines = new Vector();
078 int idx = 0;
079 for (Enumeration e=iHeader.fields();e.hasMoreElements();idx++) {
080 CSVField field = (CSVField)e.nextElement();
081 iHeaderMap.put(field.toString(),new Integer(idx));
082 }
083 String line = null;
084 while ((line=reader.readLine())!=null) {
085 if (line.trim().length()==0) continue;
086 iLines.addElement(new CSVLine(line));
087 }
088 } finally {
089 if (reader!=null) reader.close();
090 }
091 }
092
093 public void save(File file) throws IOException {
094 PrintWriter writer = null;
095 try {
096 writer = new PrintWriter(new FileWriter(file));
097 if (iHeader!=null)
098 writer.println(iHeader.toString());
099
100 if (iLines!=null) {
101 for (Enumeration e=iLines.elements();e.hasMoreElements();) {
102 Object line = e.nextElement();
103 writer.println(line.toString());
104 }
105 }
106
107 writer.flush();
108 } finally {
109 if (writer!=null) writer.close();
110 }
111 }
112
113 public CSVLine getHeader() { return iHeader; }
114 public void setHeader(CSVLine header) { iHeader = header; }
115 public Vector getLines() { return iLines; }
116 public int size() { return iLines.size(); }
117 public boolean isEmpty() { return iLines.isEmpty(); }
118 public CSVLine getLine(int idx) { return (CSVLine)iLines.elementAt(idx); }
119 public Enumeration lines() { return iLines.elements(); }
120 public void addLine(CSVLine line) {
121 if (iLines==null) iLines = new Vector();
122 iLines.addElement(line);
123 }
124 public void addLine(String line) {
125 if (iLines==null) iLines = new Vector();
126 iLines.addElement(line);
127 }
128 public Vector filter(CSVFilter filter) {
129 Vector ret = new Vector();
130 for (Enumeration e=iLines.elements();e.hasMoreElements();) {
131 CSVLine line = (CSVLine)e.nextElement();
132 if (filter.match(line))
133 ret.addElement(line);
134 }
135 return ret;
136 }
137
138 public CSVLine addLine() {
139 CSVLine line = new CSVLine();
140 addLine(line);
141 return line;
142 }
143 public CSVLine addLine(CSVField fields[]) {
144 CSVLine line = new CSVLine(fields);
145 addLine(line);
146 return line;
147 }
148 public CSVLine addLine(Collection fields) {
149 CSVLine line = new CSVLine(fields);
150 addLine(line);
151 return line;
152 }
153 public CSVLine setHeader(CSVField fields[]) {
154 CSVLine header = new CSVLine(fields);
155 setHeader(header);
156 return header;
157 }
158 public CSVLine setHeader(Collection fields) {
159 CSVLine header = new CSVLine(fields);
160 setHeader(header);
161 return header;
162 }
163
164 /** Representation of a line of a CSV file */
165 public class CSVLine implements Serializable {
166 private static final long serialVersionUID = 1L;
167 Vector iFields = new Vector(iHeader==null?10:iHeader.size());
168
169 public CSVLine(String line) {
170 int idx = 0;
171 int newIdx = 0;
172 int fromIdx = 0;
173 while ((newIdx = line.indexOf(iSeparator, fromIdx))>=0) {
174 String field = line.substring(idx, newIdx);
175 if (iQuotationMark!=null && field.startsWith(iQuotationMark) && !field.endsWith(iQuotationMark)) {
176 fromIdx = newIdx + iSeparator.length();
177 continue;
178 }
179 iFields.addElement(new CSVField(field, iQuotationMark));
180 idx = newIdx + iSeparator.length();
181 fromIdx = idx;
182 }
183 iFields.addElement(new CSVField(line.substring(idx), iQuotationMark));
184 }
185 public CSVLine() {}
186 public CSVLine(CSVField fields[]) {
187 for (int i=0;i<fields.length;i++)
188 iFields.addElement(fields[i]);
189 }
190 public CSVLine(Collection fields) {
191 iFields.addAll(fields);
192 }
193
194 public Vector getFields() { return iFields; }
195 public int size() { return iFields.size(); }
196 public boolean isEmpty() { return iFields.isEmpty(); }
197 public CSVField getField(int idx) {
198 try {
199 return (CSVField)iFields.elementAt(idx);
200 } catch (ArrayIndexOutOfBoundsException e) {
201 return null;
202 }
203 }
204 public void setField(int idx, CSVField field) {
205 iFields.setElementAt(field, idx);
206 }
207 public Enumeration fields() { return iFields.elements(); }
208 public CSVField getField(String name) {
209 Integer idx = (Integer)iHeaderMap.get(name);
210 return (idx==null?null:getField(idx.intValue()));
211 }
212 public void setField(String name, CSVField field) {
213 Integer idx = (Integer)iHeaderMap.get(name);
214 if (idx!=null) setField(idx.intValue(), field);
215 }
216 public String toString() {
217 StringBuffer sb = new StringBuffer();
218 for (Enumeration e=iFields.elements();e.hasMoreElements();) {
219 CSVField field = (CSVField)e.nextElement();
220 if (field!=null)
221 sb.append((iQuotationMark==null?"":iQuotationMark)+(field==null?"":field.toString())+(iQuotationMark==null?"":iQuotationMark));
222 if (e.hasMoreElements()) sb.append(iSeparator);
223 }
224 return sb.toString();
225 }
226 public void debug(int offset, PrintWriter out) {
227 int idx=0;
228 for (Enumeration e=iFields.elements();e.hasMoreElements();idx++) {
229 CSVField field = (CSVField)e.nextElement();
230 if (field==null || field.toString().length()==0) continue;
231 for (int i=0;i<offset;i++)
232 out.print(" ");
233 out.println(iHeader.getField(idx)+"="+(iQuotationMark==null?"":iQuotationMark)+field+(iQuotationMark==null?"":iQuotationMark));
234 }
235 }
236 }
237
238 /** Representation of a field of a CSV file */
239 public static class CSVField implements Serializable {
240 private static final long serialVersionUID = 1L;
241 String iField = null;
242 public CSVField(String field, String quotationMark) {
243 field = field.trim();
244 if (quotationMark!=null && field.startsWith(quotationMark) && field.endsWith(quotationMark))
245 field = field.substring(1, field.length()-1);
246 iField = field.trim();
247 }
248 public CSVField(Object field) { set(field==null?"":field.toString()); }
249 public CSVField(int field) { set(field); }
250 public CSVField(boolean field) { set(field); }
251 public CSVField(double field) { set(field); }
252 public CSVField(long field) { set(field); }
253 public CSVField(float field) { set(field); }
254
255 public void set(Object value) { iField = (value==null?"":value.toString()); }
256 public void set(int value) { iField = String.valueOf(value); }
257 public void set(boolean value) { iField = (value?"1":"0"); }
258 public void set(double value) { iField = String.valueOf(value); }
259 public void set(long value) { iField = String.valueOf(value); }
260 public void set(float value) { iField = String.valueOf(value); }
261
262 public String toString() { return (iField==null?"":iField); }
263 public boolean isEmpty() { return (iField.length()==0); }
264 public int toInt() { return toInt(0); }
265 public int toInt(int defaultValue) {
266 try {
267 return Integer.parseInt(iField);
268 } catch (NumberFormatException e) {
269 return defaultValue;
270 }
271 }
272 public long toLong() { return toLong(0); }
273 public long toLong(long defaultValue) {
274 try {
275 return Long.parseLong(iField);
276 } catch (NumberFormatException e) {
277 return defaultValue;
278 }
279 }
280 public double toDouble() { return toDouble(0); }
281 public double toDouble(double defaultValue) {
282 try {
283 return Double.parseDouble(iField);
284 } catch (NumberFormatException e) {
285 return defaultValue;
286 }
287 }
288 public Date toDate() {
289 int month = Integer.parseInt(iField.substring(0,2));
290 int day = Integer.parseInt(iField.substring(3,5));
291 int year = Integer.parseInt(iField.substring(6,8));
292 Calendar c = Calendar.getInstance(Locale.US);
293 c.set(year,month-1,day,0,0,0);
294 return c.getTime();
295 }
296 public boolean toBoolean() { return "Y".equalsIgnoreCase(iField) || "on".equalsIgnoreCase(iField) || "true".equalsIgnoreCase(iField) || "1".equalsIgnoreCase(iField); }
297 }
298
299 /** An interface for filtering lines of a CSV file */
300 public static interface CSVFilter {
301 public boolean match(CSVLine line);
302 }
303
304 public static CSVFilter eq(String name, String value) {
305 return (new CSVFilter() {
306 String n,v;
307 public boolean match(CSVLine line) {
308 return line.getField(n).equals(v);
309 }
310 private CSVFilter set(String n, String v) { this.n=n; this.v=v; return this; }
311 }).set(name, value);
312 }
313
314 public static CSVFilter and(CSVFilter first, CSVFilter second) {
315 return (new CSVFilter() {
316 CSVFilter a,b;
317 public boolean match(CSVLine line) {
318 return a.match(line) && b.match(line);
319 }
320 private CSVFilter set(CSVFilter a, CSVFilter b) { this.a=a; this.b=b; return this; }
321 }).set(first, second);
322 }
323
324 public static CSVFilter or(CSVFilter first, CSVFilter second) {
325 return (new CSVFilter() {
326 CSVFilter a,b;
327 public boolean match(CSVLine line) {
328 return a.match(line) || b.match(line);
329 }
330 private CSVFilter set(CSVFilter a, CSVFilter b) { this.a=a; this.b=b; return this; }
331 }).set(first, second);
332 }
333
334 public static CSVFilter not(CSVFilter filter) {
335 return (new CSVFilter() {
336 CSVFilter f;
337 public boolean match(CSVLine line) {
338 return !f.match(line);
339 }
340 private CSVFilter set(CSVFilter f) { this.f=f; return this; }
341 }).set(filter);
342 }
343 }