package org.maachang.util;

import java.util.ArrayList;

import org.apache.oro.text.perl.Perl5Util;

/**
 * 文字操作ユーティリティ.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangBase 1.00
 */
public class StringUtil {

    /**
     * チェック情報単位で情報を区切ります。 <BR>
     * <BR>
     * 
     * @param str
     *            区切り対象の情報を設置します.
     * @param check
     *            区切り対象の文字情報をセットします.<BR>
     *            区切り対象文字を複数設定する事により、それらに対応した区切りとなります.
     * @return ArrayList 区切られた情報が格納されています.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public static final ArrayList<String> cutString(String str, String check)
            throws IllegalArgumentException {
        ArrayList<String> ret = null;

        ret = new ArrayList<String>();

        cutString(ret, false, str, check);

        return ret;
    }

    /**
     * チェック情報単位で情報を区切ります。 <BR>
     * <BR>
     * 
     * @param out
     *            区切られた情報が格納されます.
     * @param str
     *            区切り対象の情報を設置します.
     * @param check
     *            区切り対象の文字情報をセットします.<BR>
     *            区切り対象文字を複数設定する事により、それらに対応した区切りとなります.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public static final void cutString(ArrayList<String> out, String str,
            String check) throws IllegalArgumentException {
        cutString(out, false, str, check);
    }

    /**
     * チェック情報単位で情報を区切ります。 <BR>
     * <BR>
     * 
     * @param mode
     *            区切られた時の文字列が無い場合に、無視するかチェックします.<BR>
     *            [true]の場合は、無視しません. [false]の場合は、無視します.
     * @param str
     *            区切り対象の情報を設置します.
     * @param check
     *            区切り対象の文字情報をセットします.<BR>
     *            区切り対象文字を複数設定する事により、それらに対応した区切りとなります.
     * @return ArrayList 区切られた情報が格納されています.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public static final ArrayList<String> cutString(boolean mode, String str,
            String check) throws IllegalArgumentException {
        ArrayList<String> ret = null;

        ret = new ArrayList<String>();

        cutString(ret, mode, str, check);

        return ret;
    }

    /**
     * チェック情報単位で情報を区切ります。 <BR>
     * <BR>
     * 
     * @param out
     *            区切られた情報が格納されます.
     * @param mode
     *            区切られた時の文字列が無い場合に、無視するかチェックします.<BR>
     *            [true]の場合は、無視しません. [false]の場合は、無視します.
     * @param str
     *            区切り対象の情報を設置します.
     * @param check
     *            区切り対象の文字情報をセットします.<BR>
     *            区切り対象文字を複数設定する事により、それらに対応した区切りとなります.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public static final void cutString(ArrayList<String> out, boolean mode,
            String str, String check) throws IllegalArgumentException {
        int i, j;
        int len;
        int lenJ;
        int s = -1;
        char strCode;

        char[] checkCode = null;
        String tmp = null;

        if (out == null || str == null || (len = str.length()) <= 0
                || check == null || check.length() <= 0) {
            throw new IllegalArgumentException("引数が不正です");
        }

        out.clear();

        lenJ = check.length();
        checkCode = new char[lenJ];
        check.getChars(0, lenJ, checkCode, 0);

        if (lenJ == 1) {

            for (i = 0, s = -1; i < len; i++) {

                strCode = str.charAt(i);
                s = (s == -1) ? i : s;

                if (strCode == checkCode[0]) {

                    if (s < i) {
                        tmp = str.substring(s, i);
                        out.add(tmp);
                        tmp = null;
                        s = -1;
                    } else if (mode == true) {
                        out.add("");
                        s = -1;
                    } else {
                        s = -1;
                    }

                }

            }

        } else {

            for (i = 0, s = -1; i < len; i++) {

                strCode = str.charAt(i);
                s = (s == -1) ? i : s;

                for (j = 0; j < lenJ; j++) {
                    if (strCode == checkCode[j]) {

                        if (s < i) {
                            tmp = str.substring(s, i);
                            out.add(tmp);
                            tmp = null;
                            s = -1;
                        } else if (mode == true) {
                            out.add("");
                            s = -1;
                        } else {
                            s = -1;
                        }

                        break;

                    }
                }

            }

        }

        if (s != -1) {

            tmp = str.substring(s, len);
            out.add(tmp);
            tmp = null;
        }

        checkCode = null;
        tmp = null;
    }

    /**
     * チェック情報単位で情報を区切ります。 <BR>
     * <BR>
     * 
     * @param cote
     *            コーテーション対応であるか設定します.<BR>
     *            [true]を設定した場合、各コーテーション ( ",' ) で囲った情報内は 区切り文字と判別しません.<BR>
     *            [false]を設定した場合、コーテーション対応を行いません.
     * @param coteFlg
     *            コーテーションが入っている場合に、コーテーションを範囲に含むか否かを 設定します.<BR>
     *            [true]を設定した場合、コーテーション情報も範囲に含みます.<BR>
     *            [false]を設定した場合、コーテーション情報を範囲としません.
     * @param str
     *            区切り対象の情報を設置します.
     * @param check
     *            区切り対象の文字情報をセットします.<BR>
     *            区切り対象文字を複数設定する事により、それらに対応した区切りとなります.
     * @return ArrayList 区切られた情報が格納されています.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public static final ArrayList<String> cutString(boolean cote,
            boolean coteFlg, String str, String check)
            throws IllegalArgumentException {
        ArrayList<String> ret = null;

        ret = new ArrayList<String>();

        cutString(ret, cote, coteFlg, str, check);

        return ret;
    }

    /**
     * チェック情報単位で情報を区切ります。 <BR>
     * <BR>
     * 
     * @param out
     *            区切られた情報が格納されます.
     * @param cote
     *            コーテーション対応であるか設定します.<BR>
     *            [true]を設定した場合、各コーテーション ( ",' ) で囲った情報内は 区切り文字と判別しません.<BR>
     *            [false]を設定した場合、コーテーション対応を行いません.
     * @param coteFlg
     *            コーテーションが入っている場合に、コーテーションを範囲に含むか否かを 設定します.<BR>
     *            [true]を設定した場合、コーテーション情報も範囲に含みます.<BR>
     *            [false]を設定した場合、コーテーション情報を範囲としません.
     * @param str
     *            区切り対象の情報を設置します.
     * @param check
     *            区切り対象の文字情報をセットします.<BR>
     *            区切り対象文字を複数設定する事により、それらに対応した区切りとなります.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public static final void cutString(ArrayList<String> out, boolean cote,
            boolean coteFlg, String str, String check)
            throws IllegalArgumentException {
        int i, j;
        int len;
        int lenJ;
        int s = -1;

        char coteChr;
        char nowChr;
        char strCode;

        char[] checkCode = null;
        String tmp = null;

        if (cote == false) {
            StringUtil.cutString(out, str, check);
        } else {

            if (out == null || str == null || (len = str.length()) <= 0
                    || check == null || check.length() <= 0) {
                throw new IllegalArgumentException("引数が不正です");
            }

            out.clear();

            lenJ = check.length();
            checkCode = new char[lenJ];
            check.getChars(0, lenJ, checkCode, 0);

            if (lenJ == 1) {
                int befCode = -1 ;
                for (i = 0, s = -1, coteChr = 0; i < len; i++) {

                    strCode = str.charAt(i);
                    nowChr = strCode;
                    s = (s == -1) ? i : s;

                    if (coteChr == 0) {

                        if (nowChr == '\'' || nowChr == '\"') {

                            coteChr = nowChr;

                            if (s < i) {
                                tmp = str.substring(s, i);
                                out.add(tmp);
                                tmp = null;
                                s = -1;
                            } else {
                                s = -1;
                            }

                        } else if (strCode == checkCode[0]) {

                            if (s < i) {
                                tmp = str.substring(s, i);
                                out.add(tmp);
                                tmp = null;
                                s = -1;
                            } else {
                                s = -1;
                            }

                        }
                    } else if (befCode!= '\\' && coteChr == nowChr) {

                        coteChr = 0;

                        if (s == i && coteFlg == true) {
                            out.add(new StringBuilder().append(strCode).append(
                                    strCode).toString());
                            s = -1;
                        } else if (s < i) {

                            if (coteFlg == true) {
                                tmp = str.substring(s - 1, i + 1);
                            } else {
                                tmp = str.substring(s, i);
                            }

                            out.add(tmp);
                            tmp = null;
                            s = -1;
                        } else {
                            s = -1;
                        }

                    }
                    befCode = strCode ;
                }
            } else {
                int befCode = -1 ;
                for (i = 0, s = -1, coteChr = 0; i < len; i++) {

                    strCode = str.charAt(i);
                    nowChr = strCode;
                    s = (s == -1) ? i : s;

                    if (coteChr == 0) {

                        if (nowChr == '\'' || nowChr == '\"') {

                            coteChr = nowChr;

                            if (s < i) {
                                tmp = str.substring(s, i);
                                out.add(tmp);
                                tmp = null;
                                s = -1;
                            } else {
                                s = -1;
                            }

                        } else {

                            for (j = 0; j < lenJ; j++) {

                                if (strCode == checkCode[j]) {

                                    if (s < i) {
                                        tmp = str.substring(s, i);
                                        out.add(tmp);
                                        tmp = null;
                                        s = -1;
                                    } else {
                                        s = -1;
                                    }

                                    break;

                                }

                            }

                        }
                    } else if (befCode != '\\' && coteChr == nowChr) {

                        coteChr = 0;

                        if (s == i && coteFlg == true) {
                            out.add(new StringBuilder().append(strCode).append(
                                    strCode).toString());
                            s = -1;
                        } else if (s < i) {

                            if (coteFlg == true) {
                                tmp = str.substring(s - 1, i + 1);
                            } else {
                                tmp = str.substring(s, i);
                            }

                            out.add(tmp);
                            tmp = null;
                            s = -1;
                        } else {
                            s = -1;
                        }

                    }
                    befCode = strCode ;
                }
            }

            if (s != -1) {

                if (coteChr != 0 && coteFlg == true) {
                    tmp = str.substring(s - 1, len) + (char) coteChr;
                } else {
                    tmp = str.substring(s, len);
                }

                out.add(tmp);
                tmp = null;

            }

            checkCode = null;
            tmp = null;

        }
    }

    /**
     * コーテーション以外の文字列の中で、指定文字で区切る. <BR>
     * <BR>
     * 
     * @param string
     *            対象文字列を設定します.
     * @param check
     *            区切り文字列群を設定します.
     * @return ArrayList<String> 区切られた文字列が返されます.
     */
    public static final ArrayList<String> parseString(String string,
            String check) {
        int cote = -1;
        int len = string.length();
        ArrayList<String> lst = new ArrayList<String>();
        StringBuilder buf = new StringBuilder();
        int lenJ = check.length();
        char b = 0;
        boolean end = false;
        for (int i = 0; i < len; i++) {
            end = false;
            char c = string.charAt(i);
            if (cote != -1) {
                buf.append(c);
                if (c == cote && ((i != 0 && b != '\\') || i == 0)) {
                    cote = -1;
                }
            } else if ((c == '\'' || c == '\"')
                    && ((i != 0 && b != '\\') || i == 0)) {
                buf.append(c);
                cote = c;
            } else {
                boolean chk = false;
                for (int j = 0; j < lenJ; j++) {
                    char x = check.charAt(j);
                    if (c == x) {
                        end = true;
                        lst.add(buf.toString().trim());
                        buf = new StringBuilder();
                        chk = true;
                        break;
                    }
                }
                if (chk == false) {
                    buf.append(c);
                }
            }
            b = c;
        }
        if (buf.length() > 0 || end == true) {
            lst.add(buf.toString().trim());
        }
        buf = null;
        return lst;
    }

    /**
     * 指定文字位置の１つ前の情報を取得. <BR>
     * <BR>
     * 
     * @param string
     *            対象の文字列を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return int 対象の文字コードが返されます.
     */
    public static final int getBefore(String string, int no) {
        if (string == null || string.length() <= 0 || no <= 0) {
            return -1;
        }
        return (int) (string.charAt(no - 1) & 0x0000ffff);
    }

    /**
     * 指定文字位置の１つ後ろの情報を取得. <BR>
     * <BR>
     * 
     * @param string
     *            対象の文字列を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return int 対象の文字コードが返されます.
     */
    public static final int getNext(String string, int no) {
        if (string == null || string.length() <= no + 1) {
            return -1;
        }
        return (int) (string.charAt(no + 1) & 0x0000ffff);
    }

    /**
     * 指定内容の文字数を取得. <BR>
     * <BR>
     * 指定内容の文字列を取得します.<BR>
     * また、コーテーション内の情報はカウントしません. <BR>
     * 
     * @param string
     *            対象の文字列を設定します.
     * @param check
     *            カウント対象のキャラクタを設定します.
     * @return int 対象の文字数が返されます.
     */
    public static final int getCount(String string, char check) {
        if (string == null || string.length() <= 0) {
            return 0;
        }
        int ret = 0;
        int cote = -1;
        char b = 0;
        int len = string.length();
        for (int i = 0; i < len; i++) {
            char c = string.charAt(i);
            if (cote != -1) {
                if (c == cote && ((i != 0 && b != '\\') || i == 0)) {
                    cote = -1;
                }
            } else if ((c == '\'' || c == '\"')
                    && ((i != 0 && b != '\\') || i == 0)) {
                cote = c;
            } else if (check == c) {
                ret++;
            }
            b = c;
        }
        return ret;
    }

    /**
     * 指定コードを置き換えます. <BR>
     * <BR>
     * 指定文字列に対して、変更対象の文字列を指定して 変更後の文字列に置き換えます. <BR>
     * 
     * @param str
     *            変更を行う文字列を指定します.
     * @param src
     *            変更対象の文字列を指定します.
     * @param dest
     *            変更後の文字列を指定します.
     * @return String 変更された文字列が返されます.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public static final String changeString(String str, String src, String dest)
            throws IllegalArgumentException {
        int pnt;
        int end;
        int srcLen;

        StringBuilder buf = null;

        if (str == null || str.length() <= 0 || src == null
                || (srcLen = src.length()) <= 0) {
            throw new IllegalArgumentException("引数は不正です");
        }

        if (dest == null || dest.length() <= 0) {
            dest = "";
        }

        buf = new StringBuilder();

        pnt = str.indexOf(src);
        if (pnt == -1) {
            return str;
        } else if (pnt == 0) {
            buf.append(dest);
            end = srcLen;
        } else {
            buf.append(str.substring(0, pnt));
            buf.append(dest);
            end = pnt + srcLen;
        }

        for (pnt += srcLen;;) {
            if ((pnt = str.indexOf(src, pnt)) == -1) {
                buf.append(str.substring(end));
                break;
            }
            if (pnt == end) {
                buf.append(dest);
            } else {
                buf.append(str.substring(end, pnt));
                buf.append(dest);
            }

            end = pnt + srcLen;
            pnt += srcLen;

        }

        return buf.toString();
    }
    
    /**
     * 文字列の前後にコーテーションが存在するかチェック.
     * @param str 対象の文字列を設定します.
     * @return boolean [true]の場合、コーテーションが存在します.
     */
    public static final boolean isCote( String str ) {
        if (str == null || str.length() <= 0) {
            return false ;
        }
        str = str.trim();
        return ((str.startsWith("\'") == true && str.endsWith("\'") == true) || (str
                .startsWith("\"") == true && str.endsWith("\"") == true)) ? true : false ;
    }

    /**
     * 文字列の前後コーテーションを削除. <BR>
     * <BR>
     * 文字列の前後コーテーションを削除します. <BR>
     * 
     * @param str
     *            変換対象の文字列を設定します.
     * @return String 変換された結果が返されます.
     */
    public static final String cutCote(String str) {
        if (str == null || str.length() <= 0) {
            if (str == null) {
                return null;
            } else {
                return "";
            }
        }

        str = str.trim();

        return ((str.startsWith("\'") == true && str.endsWith("\'") == true) || (str
                .startsWith("\"") == true && str.endsWith("\"") == true)) ? str
                .substring(1, str.length() - 1) : str;
    }

    /**
     * 指定文字から、N文字情報を取得. <BR>
     * <BR>
     * 指定文字から、N文字情報を取得します. <BR>
     * 
     * @param str
     *            対象文字列を設定します.
     * @param start
     *            対象開始位置を設定します.
     * @param length
     *            対象文字列を設定します.
     * @return String 文字列が返されます.
     */
    public static final String getNLength(String str, int start, int length) {
        return str.substring(start, ((start + length >= str.length()) ? str
                .length() : start + length))
                + "...";
    }

    /**
     * 指定文字数を生成. <BR>
     * <BR>
     * 
     * @param chr
     *            対象の文字を設定します.
     * @param length
     *            生成対象の情報数を設定します.
     * @return String 文字列が返されます.
     */
    public static final String createString(char chr, int length) {
        if (length <= 0) {
            return "";
        }
        StringBuilder buf = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            buf.append(chr);
        }
        return buf.toString();
    }
    
    /**
     * CSVを区切ります.
     * <BR>
     * @param cote [true]の場合ダブルコーテーションに統一します.
     *              [false]の場合シングルコーテーションに統一します.
     * @param line １行の内容を設定します.
     * @param cutCode 区切り文字を設定します.
     * @return ArrayList<String> 区切られた内容が返されます.
     * @exception Exception 例外.
     */
    public static final ArrayList<String> getCsv( boolean cote,String line,String cutCode )
        throws Exception {
        if( line == null || line.length() <= 0 ) {
            return new ArrayList<String>() ;
        }
        if( cutCode == null || cutCode.length() <= 0 ) {
            cutCode = "," ;
        }
        ArrayList<String> tmp = new ArrayList<String>() ;
        int p = -1 ;
        int b = 0 ;
        int cutLen = cutCode.length() ;
        for( ;; ) {
            p = line.indexOf( cutCode,b ) ;
            if( p <= -1 ) {
                if( b == 0 ) {
                    tmp.add( line ) ;
                }
                else if( line.length() > b ) {
                    tmp.add( line.substring( b ) ) ;
                }
                break ;
            }
            char c = line.charAt( b ) ;
            if( c == '\'' || c == '\"' ) {
                int x = line.indexOf( c,b+1 ) ;
                if( x <= -1 ) {
                    tmp.add( new StringBuilder().append( line.substring( b ) ).append( c ).toString() ) ;
                    break ;
                }
                tmp.add( line.substring( b,x+1 ) ) ;
                b = x + 1 + cutLen ;
            }
            else {
                tmp.add( line.substring( b,p ) ) ;
                b = p + cutLen ;
            }
        }
        ArrayList<String> ret = new ArrayList<String>() ;
        int len = tmp.size() ;
        for( int i = 0 ; i < len ; i ++ ) {
            String x = tmp.get( i ) ;
            if( cote == true && x.startsWith( "\'" ) && x.endsWith( "\'") ) {
                ret.add( new StringBuilder().append( "\"" ).
                    append( x.substring( 1,x.length()-1 ) ).
                    append( "\"" ).toString() ) ;
            }
            else if( cote == false && x.startsWith( "\"" ) && x.endsWith( "\"") ) {
                ret.add( new StringBuilder().append( "\'" ).
                    append( x.substring( 1,x.length()-1 ) ).
                    append( "\'" ).toString() ) ;
            }
            else {
                ret.add( x ) ;
            }
        }
        tmp.clear() ;
        tmp = null ;
        return ret ;
    }
    
    /**
     * ShiftJis - MS932変換表.
     */
    private static final char[] SJIS_MS932_MAP = {
        '\u301C', '\uFF5E',
        '\u2016', '\u2225',
        '\u2212', '\uFF0D',
        '\u00A2', '\uFFE0',
        '\u00A3', '\uFFE1',
        '\u00AC', '\uFFE2'
    } ;
    
    /**
     * 指定文字コードをMS932に変換.
     * @param c 変換対象の文字を設定します.
     * @return char 変換された文字が返されます.
     */
    public static final char toMS932(char c) {
        int len = SJIS_MS932_MAP.length ;
        for (int i = 0; i < len ; i += 2) {
            if (c == SJIS_MS932_MAP[i]) {
                c = SJIS_MS932_MAP[i + 1];
                break;
            }
        }
        return c;
    }
    
    /**
     * 指定文字コードをShiftJISに変換.
     * @param c 変換対象の文字を設定します.
     * @return char 変換された文字が返されます.
     */
    public static final char toSJIS(char c) {
        int len = SJIS_MS932_MAP.length ;
        for (int i = 0; i < len ; i += 2) {
            if (c == SJIS_MS932_MAP[i + 1]) {
                c = SJIS_MS932_MAP[i];
                break;
            }
        }
        return c;
    }
    
    /**
     * 指定文字列をMS932に変換.
     * @param str 変換対象の文字列を設定します.
     * @return String 変換された文字列が返されます.
     */
    public static final String toMS932(String str) {
        if (str == null) {
            return null;
        }
        char[] c = new char[str.length()];
        int len = str.length() ;
        for (int i=0; i<len; i++) {
            c[i] = toMS932(str.charAt(i));
        }
        return new String(c);
    }
    
    /**
     * 指定文字列をShiftJISに変換.
     * @param str 変換対象の文字列を設定します.
     * @return String 変換された文字列が返されます.
     */
    public static final String toSJIS(String str) {
        if (str == null) {
            return null;
        }
        char[] c = new char[str.length()];
        int len = str.length() ;
        for (int i=0; i<len; i++) {
            c[i] = toSJIS(str.charAt(i));
        }
        return new String(c);
    }
    
    /**
     * 指定文字内のコーテーションインデントをあげる.
     * @param string 対象の文字列を設定します.
     * @return String 変換された文字列が返されます.
     */
    public static final String upIndentCote( String string ) {
        if( string == null || string.length() <= 0 ) {
            return string ;
        }
        if( string.indexOf( "\'" ) != -1 || string.indexOf( "\"" ) != -1 ) {
            int len = string.length() ;
            int yenCnt = 0 ;
            StringBuilder buf = new StringBuilder() ;
            for( int i = 0 ; i < len ; i ++ ) {
                int c = ( int )( string.charAt( i ) & 0x0000ffff ) ;
                if( c == '\'' || c == '\"' ) {
                    if( yenCnt == 0 ) {
                        buf.append( "\\" ) ;
                    }
                    else {
                        buf.append( "\\\\" ) ;
                    }
                }
                buf.append( ( char)c ) ;
                if( c == '\\' ) {
                    yenCnt ++ ;
                }
                else {
                    yenCnt = 0 ;
                }
            }
            return buf.toString() ;
        }
        return string ;
    }
    
    /**
     * 前後のスペース等を取り除く.
     * @param string 対象の文字列を設定します.
     * @return String 文字列が返されます.
     */
    public static final String trim( String string ) {
        int s = -1 ;
        int e = -1 ;
        int len = string.length() ;
        s = 0 ;
        boolean sFlg = false ;
        for( int i = 0 ; i < len ; i ++ ) {
            char c = string.charAt( i ) ;
            if( c != ' '  && c != '　' && c != '\r' && c != '\n' && c != '\t' ) {
                s = i ;
                break ;
            }
            sFlg = true ;
        }
        e = len-1 ;
        boolean eFlg = false ;
        for( int i = len-1 ; i >= 0 ; i -- ) {
            char c = string.charAt( i ) ;
            if( c != ' '  && c != '　' && c != '\r' && c != '\n' && c != '\t' ) {
                e = i ;
                break ;
            }
            eFlg = true ;
        }
        if( sFlg == true && eFlg == true ) {
            return string.substring( s,e+1 ) ;
        }
        else if( sFlg == true ) {
            return string.substring( s ) ;
        }
        else if( eFlg == true ) {
            return string.substring( 0,e+1 ) ;
        }
        return string ;
    }
    
    /**
     * コーテーション内を検知しないIndexOf.
     * @param base 検索元の情報を設定します.
     * @param cc チェック対象の内容を設定します.
     * @param off 対象のオフセット値を設定します.
     * @return int 検索結果の内容が返されます.
     * @exception Exception 例外.
     */
    public static final int indexToNotCote( String base,String cc,int off ) throws Exception {
        int len = base.length() ;
        int cote = -1 ;
        char[] ck = cc.toCharArray() ;
        int cLen = ck.length ;
        char bef = 0 ;
        for( int i = off ; i < len ; i ++ ) {
            char c = base.charAt( i ) ;
            if( cote != -1 ) {
                if( bef != '\\' && c == cote ) {
                    cote = -1 ;
                }
            }
            else {
                if( bef != '\\' && ( c == '\'' || c == '\"' ) ) {
                    cote = c ;
                }
                else if( c == ck[ 0 ] ) {
                    boolean res = true ;
                    for( int j = 1 ; j < cLen ; j ++ ) {
                        if( i + j >= len || ck[ j ] != base.charAt( i + j ) ) {
                            res = false ;
                            break ;
                        }
                    }
                    if( res == true ) {
                        return i ;
                    }
                }
            }
            bef = c ;
        }
        return -1 ;
    }
    
    /**
     * カッコを検知しないIndexOf.
     * @param base 検索元の情報を設定します.
     * @param cc チェック対象の内容を設定します.
     * @param st カッコ開始文字列を設定します.
     * @param ed カッコ終了文字列を設定します.
     * @param off 対象のオフセット値を設定します.
     * @return int 検索結果の内容が返されます.
     * @exception Exception 例外.
     */
    public static final int indexToNotPar( String base,String cc,char st,char ed,int off ) throws Exception {
        int len = base.length() ;
        int par = -1 ;
        char[] ck = cc.toCharArray() ;
        int cLen = ck.length ;
        int idx = 0 ;
        for( int i = off ; i < len ; i ++ ) {
            char c = base.charAt( i ) ;
            if( par != -1 ) {
                if( c == ed ) {
                    idx -- ;
                    if( idx <= 0 ) {
                        par = -1 ;
                    }
                }
                else if( c == st ) {
                    idx ++ ;
                }
            }
            else {
                if( c == st ) {
                    idx = 1 ;
                    par = c ;
                }
                else if( c == ck[ 0 ] ) {
                    boolean res = true ;
                    for( int j = 1 ; j < cLen ; j ++ ) {
                        if( i + j >= len || ck[ j ] != base.charAt( i + j ) ) {
                            res = false ;
                            break ;
                        }
                    }
                    if( res == true ) {
                        return i ;
                    }
                }
            }
        }
        return -1 ;
    }
    
    /**
     * 指定カッコの終端を検知.
     * @param base 検索元の情報を設定します.
     * @param st カッコ開始文字列を設定します.
     * @param ed カッコ終了文字列を設定します.
     * @param off 対象のオフセット値を設定します.
     * @return int 検索結果の内容が返されます.
     * @exception Exception 例外.
     */
    public static final int indexParAndCote( String base,char st,char ed,int off ) throws Exception {
        int len = base.length() ;
        int par = -1 ;
        int cote = -1 ;
        int idx = 0 ;
        for( int i = off ; i < len ; i ++ ) {
            char c = base.charAt( i ) ;
            if( par != -1 || cote != -1 ) {
                if( cote != -1 ) {
                    if( c == cote ) {
                        cote = -1 ;
                    }
                }
                else if( par != -1 ) {
                    if( c == ed ) {
                        idx -- ;
                        if( idx <= 0 ) {
                            return i ;
                        }
                    }
                    else if( c == st ) {
                        idx ++ ;
                    }
                }
            }
            else {
                if( c == '\'' || c == '\"' ) {
                    cote = c ;
                }
                else if( c == st ) {
                    idx = 1 ;
                    par = c ;
                }
                else if( c == ed ) {
                    return i ;
                }
            }
        }
        return -1 ;
    }
    
    /**
     * チェックタイプ : 数字.
     */
    public static final int CHECK_NUMBER = 0x00000001 ;
    
    /**
     * チェックタイプ : 英字.
     */
    public static final int CHECK_ALPHABET = 0x00000002 ;
    
    /**
     * チェックタイプ : Asciiのみ.
     */
    public static final int CHECK_ASCII = 0x00000004 ;
    
    /**
     * チェックタイプ : カナのみ.
     */
    public static final int CHECK_KANA = 0x00000008 ;
    
    /**
     * チェックタイプ : ひらがなのみ.
     */
    public static final int CHECK_HIRA = 0x00000010 ;
    
    /**
     * タイプ判別.
     * @param type チェック対象のタイプを設定します.
     * @param chkString チェック対象の文字列を設定します.
     */
    public static boolean checkType( int type,String chkString ) {
        if( chkString == null || ( chkString = chkString.trim() ).length() <= 0 ) {
            return false ;
        }
        int len = chkString.length() ;
        switch( type ) {
            case CHECK_NUMBER :
                int cnt = 0 ;
                for( int i = 0 ; i < len ; i ++ ) {
                    char c = chkString.charAt( i ) ;
                    if( ( c >= '0' && c <= '9' ) == false ) {
                        if( c == '-' ) {
                            if( i != 0 ) {
                                return false ;
                            }
                        }
                        else if( c == '.' ) {
                            if( cnt != 0 ) {
                                return false ;
                            }
                            cnt ++ ;
                        }
                        else {
                            return false ;
                        }
                    }
                }
                return true ;
            case CHECK_ALPHABET :
                for( int i = 0 ; i < len ; i ++ ) {
                    char c = chkString.charAt( i ) ;
                    if( ( ( c >= 'a' && c <= 'z' ) ||
                        ( c >= 'A' && c <= 'Z' ) ) == false ) {
                        return false ;
                    }
                }
                return true ;
            case CHECK_ASCII :
                for( int i = 0 ; i < len ; i ++ ) {
                    char c = chkString.charAt( i ) ;
                    if( c > ( char )0x00ff ) {
                        return false ;
                    }
                }
                return true ;
            case CHECK_KANA :
                for( int i = 0 ; i < len ; i ++ ) {
                    String c = chkString.substring( i,i+1 ) ;
                    if( "アィイウウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヲンー".indexOf( c ) == -1 ) {
                        return false ;
                    }
                }
                return true ;
            case CHECK_HIRA :
                for( int i = 0 ; i < len ; i ++ ) {
                    String c = chkString.substring( i,i+1 ) ;
                    if( "あぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんー".indexOf( c ) == -1 ) {
                        return false ;
                    }
                }
                return true ;
        }
        return false ;
    }
    
    private static final Perl5Util p5util = new Perl5Util() ;
    
    /**
     * 正規表現チェック.
     * @param match 正規表現を設定します.
     * @param src 対象の文字列を設定します.
     * @return boolean [true]の場合、一致していません.
     */
    public static boolean isMatch( String match,String src ) {
        try {
            if( match == null || match.length() <= 0 ) {
                return false ;
            }
            if( src == null || ( src = src.trim() ).length() <= 0 ) {
                return false ;
            }
            return !( p5util.match( match,src ) ) ;
        } catch( Exception e ) {
            return true ;
        }
    }
}
