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 }