/* * Copyright 2006-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package egovframework.rte.bat.core.item.file.transform; import java.util.ArrayList; import java.util.List; import org.springframework.util.Assert; /** * EgovDelimitedLengthTokenizer 클래스 * @author 실행환경 개발팀 이도형 * @since 2012.07.20 * @version 1.0 * @see * <pre> * 개정이력(Modification Information) * * 수정일 수정자 수정내용 * ------- -------- --------------------------- * 2012.07.20 이도형 최초 생성 * </pre> */ public class EgovDelimitedLineTokenizer extends EgovAbstractLineTokenizer { // 기본으로 설정 가능한 delimiter. (기본: 콤마) public static final String DELIMITER_COMMA = ","; // 기본으로 설정 가능한 quotation. (기본: 쌍따옴표) public static final String DEFAULT_QUOTE_CHARACTER = "\""; // Token 생성시 사용할 delimiter. private String delimiter; // Token 생성시 사용할 quotation. private String quoteCharacter = DEFAULT_QUOTE_CHARACTER; /** * EgovDelimietedLineTokenizer 기본 생성자 * Token 생성시 사용할 delimiter로 콤마(기본 delimiter)를 사용하도록 설정한다. * * @see #DELIMITER_COMMA */ public EgovDelimitedLineTokenizer() { this(DELIMITER_COMMA); } /** * EgovDelimietedLineTokenizer 생성자 * Token 생성시 사용할 delimiter를 인수로 받아 사용하도록 설정한다. * * @param delimiter : delimiter로 사용 할 문자열 */ public EgovDelimitedLineTokenizer(String delimiter) { Assert.state(delimiter != DEFAULT_QUOTE_CHARACTER, "[" + DEFAULT_QUOTE_CHARACTER + "] is not allowed as delimiter for tokenizers."); this.delimiter = delimiter; setQuoteCharacter(DEFAULT_QUOTE_CHARACTER); } /** * Delimiter 문자열을 설정한다. * * @param delimiter : delimiter로 사용 할 문자열 */ public void setDelimiter(String delimiter) { this.delimiter = delimiter; } /** * Quotation 문자열을 설정한다. * quotation 문자는 CSV 파일에서 여러 개의 delimiter가 하나의 셀(Token)에 들어갈 경우, * 이를 하나의 Token 으로 묶어주기 위해 사용된다. * * @param quoteCharacter : quotation으로 사용 할 문자열 */ public final void setQuoteCharacter(String quoteCharacter) { this.quoteCharacter = quoteCharacter; } /** * String 형태의 line을 delimiter기준으로 token으로 만든다. * * @param String : ItemReader에서 읽어들인 line * @return List<String> : tokens */ public List<String> doTokenize(String line) { List<String> tokens = new ArrayList<String>(); int beginIndex = 0; int delimiterIndex =0; int quoteIndex = line.indexOf(quoteCharacter, beginIndex); int endQuoteIndex = 0; int lastCut = 0; int length = line.length(); while(lastCut != length && lastCut != -1) { delimiterIndex = line.indexOf(delimiter, beginIndex); // 문자열에 quotation 문자열을 체크한다 if(quoteIndex == -1 ) { lastCut = (delimiterIndex != -1 ? delimiterIndex : length); tokens.add(line.substring(beginIndex, lastCut)); beginIndex = lastCut+1; } else { if(quoteIndex < delimiterIndex){ // delimiter보다 앞에 있는 quotation을 발견했을 경우, 이는 첫 quotation(여는 quotation)이므로 다음 quotation(닫는 quotation)을 찾는다. endQuoteIndex = line.indexOf(quoteCharacter, quoteIndex + 1); if(endQuoteIndex != -1) { // 닫는 quotation을 발견했으면 하나의 token 으로 처리한다. tokens.add(line.substring(quoteIndex + 1, endQuoteIndex)); // 마지막 token 인지 체크하여 마지막 token 이라면 끝내고, 아니라면 마지막 자른 위치를 닫는 quotation 문자열 다음 식별자로 한다. if(line.indexOf(quoteCharacter, endQuoteIndex) != -1) { lastCut = line.indexOf(delimiter, endQuoteIndex); beginIndex = lastCut+1; } } else { // 닫는 quotation이 없다면 모든 token 을 하나로 처리한다. lastCut = length; tokens.add(line.substring(beginIndex, lastCut)); } } else{ // quotation이 delimiter보다 뒤에 있으면 해당 delimiter를 기준으로 자른다. lastCut = (delimiterIndex != -1 ? delimiterIndex : length); tokens.add(line.substring(beginIndex, lastCut)); beginIndex = lastCut+1; } quoteIndex = line.indexOf(quoteCharacter, beginIndex); } } return tokens; } }