    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 */
    016package org.opengion.fukurou.util;
    017
    018import java.io.BufferedReader;
    019import java.io.PrintWriter;
    020import java.io.File;
    021import java.io.IOException;
    022
    023/**
    024 * CommentLineParser.java は、ファイルを行単位に処理して、コメントを除去するクラスです。
    025 * １行分の文字列を読み取って、コメント部分を削除した文字列を返します。
    026 *
    027 * ブロックコメントの状態や、コメント除外の状態を管理しています。
    028 * オブジェクト作成後、line( String ) メソッドに、ファイルから読み取った１行分の文字列を渡せば、
    029 * コメントが除外された形で返されます。
    030 * 行として存在しない場合は、null を返します。
    031 *
    032 * @og.rev 5.7.4.0 (2014/03/07) 新規追加
    033 * @og.group ユーティリティ
    034 *
    035 * @version  6.0
    036 * @author       Kazuhiko Hasegawa
    037 * @since    JDK7.0,
    038 */
    039public class CommentLineParser {
    040        private String LINE_CMNT   = "//" ;             // ラインコメント
    041        private String BLOCK_CMNT1 = "/*" ;             // ブロックコメントの開始
    042        private String BLOCK_CMNT2 = "*/" ;             // ブロックコメントの終了
    043        private char   ESC_CHAR    = '"'  ;             // コメント除外(プログラム等で使用)
    044
    045        private boolean escIn   = false;                // コメント除外中かどうか
    046        private boolean blockIn = false;                // ブロックコメントが継続しているかどうか
    047        private boolean rtnOnly = false;                // 前の行が改行のみだったかどうか。
    048
    049        /**
    050         * コメントの種類を指定します。何も指定しない場合は、Javaコメントを初期値で設定します。
    051         *
    052         * Javaの場合は、順番に、&#47;&#47; , /&#042; , &#042;/ , &#034;(二重引用符) になります。
    053         * JavaScriptなら、&#47;&#47; , &lt;!-- , --&gt; , &#034;
    054         * ORACLEなら、-- , /&#042; , &#042;/ , &#034;(一重引用符) になります。
    055         *
    056         * ※ サブクラスで分けてもよかったのですが、とりあえず引数私にしました。
    057         *
    058         * @og.rev 5.7.4.0 (2014/03/07) 新規追加
    059         *
    060         * @param       lineCmnt        ラインコメント
    061         * @param       blockCmnt1      ブロックコメントの開始
    062         * @param       blockCmnt2      ブロックコメントの終了
    063         * @param       escChar         コメント除外(プログラム等で使用)
    064         */
    065        public void init( final String lineCmnt,final String blockCmnt1,final String blockCmnt2,final char escChar ) {
    066                LINE_CMNT   = lineCmnt ;                // ラインコメント
    067                BLOCK_CMNT1 = blockCmnt1 ;              // ブロックコメントの開始
    068                BLOCK_CMNT2 = blockCmnt2 ;              // ブロックコメントの終了
    069                ESC_CHAR    = escChar  ;                // コメント除外(プログラム等で使用)
    070        }
    071
    072        /**
    073         * １行分の文字列を読み取って、コメント部分を削除した文字列を返します。
    074         * 行として存在しない場合は、null を返します。
    075         *
    076         * @og.rev 5.7.4.0 (2014/03/07) 新規追加
    077         *
    078         * @param       inLine １行の文字列
    079         * @return      コメント削除後の１行の文字列
    080         */
    081        public String line( final String inLine ) {
    082                if( inLine == null ) { return null; }
    083
    084                int size = inLine.length();
    085
    086                StringBuilder buf = new StringBuilder( size );
    087
    088                for( int st=0; st<size; st++ ) {
    089                        char ch = inLine.charAt(st);
    090
    091                        // ブロック外で、エスケープ文字の場合は、内外反転
    092                        if( !blockIn && ESC_CHAR == ch ) { escIn = !escIn ; }
    093
    094                        if( !escIn ) {                                                                          // エスケープ外ら、処理を進める
    095                                // ブロックコメント継続中
    096                                if( blockIn ) {
    097                                        int ed = inLine.indexOf( BLOCK_CMNT2,st ) ;             // 終了を見つける
    098                                        if( ed >= 0 ) {                                                                      // 終了があれば、そこまで進める。
    099                                                blockIn = false;
    100                                                st = ed+BLOCK_CMNT2.length();
    101                                                continue;                                                                       // ブロックコメント脱出。再読み込み
    102                                        }
    103                                        break;                                                                                  // ブロックコメント未発見。次の行へ
    104                                }
    105
    106                                // ラインコメント発見。次の行へ
    107                                if( inLine.startsWith( LINE_CMNT,st ) ) { break; }
    108
    109                                // ブロックコメントを見つける
    110                                if( inLine.startsWith( BLOCK_CMNT1,st ) ) {
    111                                        int ed = inLine.indexOf( BLOCK_CMNT2,st ) ;             // 終了を見つける
    112                                        if( ed >= 0 ) {
    113                                                st = ed+BLOCK_CMNT2.length();
    114                                                continue;                                                                       // ブロックコメント脱出。再読み込み
    115                                        }
    116                                        else {
    117                                                blockIn = true;
    118                                        }
    119                                        break;                                                                                  // ブロックコメント未発見。次の行へ
    120                                }
    121                        }
    122
    123                        // 通常の文字なので、追加する。
    124                        buf.append( ch );
    125                }
    126
    127                // rTrim() と同等の処理
    128                int len = buf.length();
    129                while( 0 < len && buf.charAt(len-1) <= ' ' ) {
    130                        len--;
    131                }
    132                buf.setLength( len );
    133
    134                String rtn = null;
    135                // 長さが 0 の行は、連続で現れないようにします。
    136                if( len == 0 ) {
    137                        if( !rtnOnly ) {
    138                                rtnOnly = true;
    139                                rtn = "";
    140                        }
    141                }
    142                else {
    143                        rtnOnly = false;
    144                        rtn = buf.toString();
    145                }
    146
    147                return rtn ;
    148        }
    149
    150        /**
    151         * このクラスの動作確認用の、main メソッドです。
    152         *
    153         * Usage: java org.opengion.fukurou.util.CommentLineParser inFile outFile [encode]
    154         *
    155         * @param       args    コマンド引数配列
    156         */
    157        public static void main( final String[] args ) {
    158                if( args.length < 2 ) {
    159                        System.out.println( "Usage: java org.opengion.fukurou.util.CommentLineParser inFile outFile [encode]" );
    160                }
    161
    162                File inFile  = new File( args[0] );
    163                File outFile = new File( args[1] );
    164                String encode  = (args.length >= 3 ) ? args[3] : "UTF-8" ;
    165
    166                BufferedReader reader = FileUtil.getBufferedReader( inFile ,encode );
    167                PrintWriter    writer = FileUtil.getPrintWriter(   outFile ,encode );
    168
    169                CommentLineParser clp = new CommentLineParser();
    170
    171                try {
    172                        String line1;
    173                        while((line1 = reader.readLine()) != null) {
    174                                line1 = clp.line( line1 );
    175                                if( line1 != null ) {
    176                                        writer.println( line1 );
    177                                }
    178                        }
    179                }
    180                catch( IOException ex ) {
    181                        String errMsg = "ファイルコピー中に例外が発生しました。\n"
    182                                                + " inFile=[" + inFile + "] , outFile=[" + outFile + "]\n" ;
    183                        throw new RuntimeException( errMsg,ex );
    184                }
    185                finally {
    186                        Closer.ioClose( reader ) ;
    187                        Closer.ioClose( writer ) ;
    188                }
    189        }
    190}