001 /*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016 package org.opengion.fukurou.util;
017
018 import java.util.NoSuchElementException;
019
020 /**
021 * CSVTokenizer は、CSVファイルの??タを?次?する StringTokenizer と非常に
022 * 良く似たクラスです?
023 *
024 * StringTokenizer では、デリミタが?続する?合も?つの?ミタとするため?
025 * ??タが存在しな??合?表現が?来ませんでした?例えば、AA,BB,,DD など)
026 * また??ミタをデータ中に含??合?処?出来ません? AA,BB,"cc,dd",EE など)
027 * こ?、CSVTokenizer クラスでは、データが存在しな??合もト?クンとして返します?
028 * また??ルコー??ション("")で囲まれた?の?ミタは無視します?
029 * ただし??ミタとしては、常に?種類? cher ??しか?できません?
030 *
031 * @version 4.0
032 * @author Kazuhiko Hasegawa
033 * @since JDK5.0,
034 */
035 public class CSVTokenizer {
036 private int currentPosition;
037 private int maxPosition;
038 private String str;
039 private char delimChar ;
040 private boolean inQuoteFlag ; // "" クオート??行うかど?
041
042 /**
043 * CSV 形式? ??を解析す?CSVTokenizer のインスタンスを作?する?
044 *
045 * @param str CSV形式??? 改行コードを含まな??
046 * @param delim 区????文字?み?可)
047 * @param inQuote クオート??行うかど? [true:行う/false:行わない]
048 */
049 public CSVTokenizer( final String str, final char delim, final boolean inQuote ) {
050 currentPosition = 0;
051 this.str = str;
052 maxPosition = str.length();
053 delimChar = delim;
054 inQuoteFlag = inQuote;
055 }
056
057 /**
058 * CSV 形式? ??を解析す?CSVTokenizer のインスタンスを作?する?
059 *
060 * @param str CSV形式??? 改行コードを含まな??
061 * @param delim 区????文字?み?可)
062 */
063 public CSVTokenizer( final String str, final char delim ) {
064 this(str, delim, true);
065 }
066
067 /**
068 * CSV 形式? ??を解析す?CSVTokenizer のインスタンスを作?する?
069 *
070 * @param str CSV形式??? 改行コードを含まな??
071 */
072 public CSVTokenizer( final String str ) {
073 this(str, ',', true);
074 }
075
076 /**
077 * 次のカンマがある位置を返す?
078 * カンマが残って???合? skipDelimiters() == maxPosition となる?
079 * また最後??が空の場合も skipDelimiters() == maxPosition となる?
080 *
081 * @param startPos 検索を開始する位置
082 *
083 * @return 次のカンマがある位置。カンマがな??合?、文字?の
084 * 長さ?値となる?
085 */
086 private int skipDelimiters( final int startPos ) {
087 boolean inquote = false;
088 int position = startPos;
089 while (position < maxPosition) {
090 char ch = str.charAt(position);
091 if(!inquote && ch == delimChar) {
092 break;
093 } else if('"' == ch && inQuoteFlag) {
094 inquote = !inquote; // "" クオート??行う
095 }
096 position ++;
097 }
098 return position;
099 }
100
101 /**
102 * ト?クナイザの??で利用できるト?クンがま?るかど?を判定します?
103 * こ?メソ??true を返す場合?それ以降?引数のな?nextToken への
104 * 呼び出し?適?ト?クンを返します?
105 *
106 * @return ????現在の位置の後ろに 1 つ以上?
107 * ト?クンがある?合だ?true、そ?な??合? false
108 */
109 public boolean hasMoreTokens() {
110 int newPosition = skipDelimiters(currentPosition);
111 return ( newPosition <= maxPosition ); // "<" ?末尾の?を正しく処?きな?
112 }
113
114 /**
115 * ??ト?クナイザから次のト?クンを返します?
116 *
117 * @og.rev 5.2.0.0 (2010/09/01) ト?クンの前後が '"'である場合?"で囲われた文字?中の""は"に変換します?
118 *
119 * @return ??ト?クナイザからの次のト?クン
120 * @throws NoSuchElementException ト?クナイザの??に
121 * ト?クンが残って????
122 */
123 public String nextToken() {
124 // ">=" では末尾の?を正しく処?きな??
125 // 末尾の?が空(カンマで1行が終わ?場合?例外が発生して
126 // しま??で?
127 if(currentPosition > maxPosition) {
128 throw new NoSuchElementException(toString()+"#nextToken");
129 }
130
131 // 3.5.4.7 (2004/02/06)
132 int from = currentPosition;
133 int to = skipDelimiters(currentPosition);
134 currentPosition = to + 1;
135 // 5.2.0.0 (2010/09/01) ト?クンの前後が '"'である場合?"で囲われた文字?中の""は"に変換します?
136 String rtn = null;
137 // 3.5.5.8 (2004/05/20) ト?クンの前後が '"' なら?削除します?
138 if( inQuoteFlag && from < maxPosition && from < to &&
139 str.charAt(from) == '"' && str.charAt(to-1) == '"' ) {
140 from++;
141 to--;
142 rtn = str.substring( from,to ).replace( "\"\"", "\"" );
143 }
144 else {
145 rtn = str.substring( from,to );
146 }
147 // return str.substring( from,to );
148 return rtn;
149 }
150
151 /**
152 * 例外を生?せずにト?クナイザの <code>nextToken</code> メソ?を呼び出せる
153 * 回数を計算します?現在の位置は進みません?
154 *
155 * @return 現在の区??を適用したときに??に残って?ト?クンの数
156 * @see CSVTokenizer#nextToken()
157 */
158 public int countTokens() {
159 int count = 1;
160 int currpos = 0;
161 while ((currpos = skipDelimiters(currpos)) < maxPosition) {
162 currpos++;
163 count++;
164 }
165 return count;
166 }
167
168 /**
169 * インスタンスの??表現を返す?
170 *
171 * @return インスタンスの??表現?
172 */
173 @Override
174 public String toString() {
175 return "CSVTokenizer(" + str + ")";
176 }
177 }