jef.tools.StringUtils.java Source code

Java tutorial

Introduction

Here is the source code for jef.tools.StringUtils.java

Source

/*
 * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com)
 *
 * 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 jef.tools;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.zip.CRC32;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.math.NumberUtils;

import jef.common.BooleanList;
import jef.common.DoubleList;
import jef.common.FloatList;
import jef.common.IntList;
import jef.common.LongList;
import jef.tools.string.RegexpUtils;
import jef.tools.string.StringSpliter;
import jef.tools.string.Substring;

public final class StringUtils extends org.apache.commons.lang.StringUtils {
    public static final byte CR = 0x0D;
    public static final byte LF = 0x0A;
    public static final byte[] CRLF = { CR, LF };
    public static final String CRLF_STR = "\r\n";
    private static final String[] ISO1_SYMBOL = new String[] { "‘", "’", "”", "“",
            "…" };
    private static final String[] ASCII_SYMBOL = new String[] { "'", "'", "\"", "\"", "--" };
    private static final String EXTEND_ISO_CHAR = new String(new char[] { (char) 146, (char) 147, (char) 148 });
    private static final String EXTEND_ISO_CHAR_MAPPING = (char) 39 + "\"\"";
    private static final String invalidCharsInFilename = "\t\\/|\"*?:<>\t\n\r";// ???

    // ---------------------------------------------------------------------
    // General convenience methods for working with Strings
    // ---------------------------------------------------------------------

    /**
     * ??nullnull??
     * 
     * @param o1
     * @param o2
     * @return
     */
    public static <T extends Comparable<T>> int compareNull(T o1, T o2) {
        if (o1 == null && o2 == null)
            return 0;
        if (o1 == null)
            return -1;
        if (o2 == null)
            return 1;
        return o1.compareTo(o2);
    }

    /**
     * ?2  getLengthInBytes("") = 4
     * getLengthInBytes("?OK") = 6 getLengthInBytes(" ") = 10
     * 
     * @param str
     * @return
     */
    public static int getLengthInBytes(String str) {
        if (str == null)
            return 0;
        int len = 0;
        int max = str.length();
        for (int i = 0; i < max; i++) {
            char c = str.charAt(i);
            if (c > 255 && c != 65279) {
                len++;
            }
        }
        return str.length() + len;
    }

    /**
     * ??
     * 
     * @param text
     * @param searchString
     * @param replacement
     * @return
     */
    public static String replaceLast(String text, String searchString, String replacement) {
        if (isEmpty(text))
            return text;
        int n = text.lastIndexOf(searchString);
        if (n < 0)
            return text;
        StringBuilder sb = new StringBuilder(text.length() - searchString.length() + replacement.length());
        sb.append(text.substring(0, n));
        sb.append(replacement);
        sb.append(text.substring(n + searchString.length()));
        return sb.toString();
    }

    /**
     * ??
     * 
     * @param text
     *            
     * @param searchString
     *            
     * @param replacement
     *            ??
     * @return ??
     */
    public static String replaceLast(String text, char searchString, char replacement) {
        if (isEmpty(text))
            return text;
        int n = text.lastIndexOf(searchString);
        if (n < 0)
            return text;
        StringBuilder sb = new StringBuilder(text.length());
        sb.append(text.substring(0, n));
        sb.append(replacement);
        sb.append(text.substring(n + 1));
        return sb.toString();
    }

    /**
     * [offset,offset+length)??replacement
     * 
     * @param text
     * @param replacement
     * @param offset
     *            :[0,text.length-1]
     * @param length
     *            :<=text.length
     * @return ??
     */
    public static String replace(String text, char replacement, int offset, int length) {
        if (isEmpty(text) || offset >= text.length() || length <= 0)
            return text;
        if (offset < 0)
            offset = 0;
        int end = offset + length;
        if (end > text.length())
            end = text.length();

        char chars[] = text.toCharArray();
        for (int i = offset; i < end; i++)
            chars[i] = replacement;
        return new String(chars);
    }

    /**
     * [offset,offset+length)??fixedreplacement
     * 
     * @param text
     *            
     * @param replacement
     *            ?
     * @param fixed
     *            
     * @param offset
     *            ??
     * @param length
     *            ?
     * @return
     */
    public static String replace(String text, char replacement, int fixed, int offset, int length) {
        if (isEmpty(text) || offset >= text.length() || length <= 0)
            return text;
        if (offset < 0)
            offset = 0;
        int end = offset + length;
        if (end > text.length())
            end = text.length();

        String left = text.substring(0, offset);
        String right = text.substring(end);

        char chars[] = new char[fixed];
        for (int i = 0; i < fixed; i++)
            chars[i] = replacement;

        return concat(left, new String(chars), right);
    }

    /**
     * ??StringBuilder
     * 
     * @param e
     * @param sb
     */
    public static void exceptionSummary(Throwable e, StringBuilder sb) {
        String msg = e.getLocalizedMessage();
        StackTraceElement[] stacks = e.getStackTrace();
        if (msg == null && e.getCause() != null) {
            exceptionSummary(e.getCause(), sb);
        }
        String stack = stacks.length > 0 ? stacks[0].toString() : "";
        sb.append(e.getClass().getSimpleName()).append(':').append(msg).append('\n').append(stack);
    }

    /**
     * ??
     * 
     * @param e
     * @return
     */
    public static String exceptionSummary(Throwable e) {
        String msg = e.getLocalizedMessage();
        StackTraceElement[] stacks = e.getStackTrace();
        if (msg == null && e.getCause() != null) {
            msg = exceptionSummary(e.getCause());
        }
        String stack = stacks.length > 0 ? stacks[0].toString() : "";
        return StringUtils.concat(e.getClass().getSimpleName(), ":", msg, "\r\n", stack);
    }

    /**
     * ??String
     * 
     * @param e
     * @param pkgStart
     * @return
     */
    public static String exceptionStack(Throwable e, final String... pkgStart) {
        return exceptionStack("\r\n", e, pkgStart);
    }

    /**
     * ??String
     * 
     * @param cr
     *            ?
     * @param e
     *            
     * @param pkgStart
     *            ??
     * @return
     */
    public static String exceptionStack(final String cr, Throwable e, final String... pkgStart) {
        StringWriter w = new StringWriter();
        e.printStackTrace(new PrintWriter(w) {
            @Override
            public void println() {
            }

            @Override
            public void write(String x) {
                x = rtrim(x, '\r', '\n', '\t');
                if (x.length() == 0) {
                    return;
                }
                if (pkgStart.length == 0) {
                    super.write(x, 0, x.length());
                    super.write(cr, 0, cr.length());
                    return;
                }
                String y = x.trim();
                if (!y.startsWith("at ")) {
                    super.write(x, 0, x.length());
                    super.write(cr, 0, cr.length());
                    return;
                }
                for (String s : pkgStart) {
                    if (matchChars(y, 3, s)) {
                        super.write(x, 0, x.length());
                        super.write(cr, 0, cr.length());
                        return;
                    }
                }
            }
        });
        w.flush();
        IOUtils.closeQuietly(w);
        return w.getBuffer().toString();
    }

    /**
     * ??
     * 
     * @param source
     * @param offset
     * @param keyword
     * @return
     */
    public static boolean matchChars(CharSequence source, int offset, CharSequence keyword) {
        int max = offset + keyword.length();
        for (int i = offset; i < max; i++) {
            if (source.charAt(i) != keyword.charAt(i - offset)) {
                return false;
            }
        }
        return true;
    }

    /**
     * \\uxxxxunicode?Asc2Native
     * 
     * @return
     * @throws IOException
     */
    public static String fromHexUnicodeString(String source) throws IOException {
        StringReader in = new StringReader(source);
        int len = source.length();
        StringWriter result = new StringWriter((len > 32) ? len / 2 : 16);
        fromHexUnicodeString(in, result);
        return result.toString();
    }

    /**
     * ?\\uxxxx?,?Native2AscII
     * 
     * @param source
     * @return
     */
    public static String toHexUnicodeString(String source) {
        StringWriter out = new StringWriter(source.length() * 4);
        StringReader in = new StringReader(source);
        toHexUnicodeString(in, out, "\\u");
        return out.toString();
    }

    /**
     * ?{?}xxxx?
     * 
     * @param source
     * @return
     */
    public static String toHexUnicodeString(String source, String prefix) {
        StringWriter out = new StringWriter(source.length() * 4);
        StringReader in = new StringReader(source);
        toHexUnicodeString(in, out, prefix);
        return out.toString();
    }

    /**
     * ?{?}xxxx?(xxxx??unicode)
     * 
     * @param source
     * @return
     */
    public static void toHexUnicodeString(Reader in, Writer out, String prefix) {
        int i;
        try {
            while ((i = in.read()) > 0) {
                if (i > 255) {
                    out.write(prefix);
                    String s = Integer.toHexString(i);
                    if (s.length() == 3)
                        out.write('0');
                    out.write(s);
                } else {
                    out.write((char) i);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * \\uxxxx?
     * 
     * @return
     * @throws IOException
     */
    public static void fromHexUnicodeString(Reader in, Writer result) throws IOException {
        char[] buffer = new char[4];
        int i;
        while ((i = in.read()) > 0) {
            if (i == '\\') {
                i = in.read();
                if (i == 'u') {
                    int count = in.read(buffer);
                    if (count == 4) {
                        String unicode = new String(buffer);
                        char uni = (char) Integer.valueOf(unicode, 16).intValue();
                        result.write(uni);
                    } else {//
                        result.write("\\u");
                        result.write(buffer, 0, count);
                    }
                } else {
                    result.write('\\');
                    if (i >= 0)
                        result.write((char) i);
                }
            } else {
                result.write((char) i);
            }
        }
    }

    /**
     * ????????
     * 
     * @param base
     *            
     * @param exists
     *            
     * @param allowRaw
     *            ?????
     * @param appendFormat
     *            ??
     * @return
     */
    public static String escapeName(String base, String[] exists, boolean allowRaw, String appendFormat,
            int start) {
        if (allowRaw && !ArrayUtils.contains(exists, base)) {
            return base;
        }
        int n = start;
        while (ArrayUtils.contains(exists, base + (appendFormat == null ? n : String.format(appendFormat, n)))) {
            n++;
        }
        return base + (appendFormat == null ? n : String.format(appendFormat, n));
    }

    /**
     * ISO8859???ASCII ???
     * 
     * @param line
     * @return
     */
    public static String ISO8859ToASCII(String line) {
        line = replaceEach(line, ISO1_SYMBOL, ASCII_SYMBOL);
        line = replaceChars(line, EXTEND_ISO_CHAR, EXTEND_ISO_CHAR_MAPPING);
        return line;
    }

    /**
     * ?????
     * 
     * @param data
     * @param encode
     * @return
     */
    public static String convert(byte[] data, String encode) {
        try {
            return new String(data, encode);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 
     * 
     * @param str
     * @param notremove
     * @return
     */
    public static String removeCharsExcept(String str, char... notremove) {
        if (isEmpty(str))
            return str;
        char chars[] = str.toCharArray();
        int pos = 0;
        for (int i = 0; i < chars.length; i++)
            if (ArrayUtils.contains(notremove, chars[i]))
                chars[pos++] = chars[i];
        return new String(chars, 0, pos);
    }

    /**
     * 
     * 
     * @param str
     * @param remove
     * @return
     */
    public static String removeChars(String str, char... remove) {
        if (isEmpty(str))
            return str;
        char chars[] = str.toCharArray();
        int pos = 0;
        for (int i = 0; i < chars.length; i++)
            if (!ArrayUtils.contains(remove, chars[i]))
                chars[pos++] = chars[i];
        return new String(chars, 0, pos);
    }

    /**
     * URL?
     * 
     * @param source
     * @param charset
     * @return
     */
    public static String urlDecode(String source, String charset) {
        try {
            return URLDecoder.decode(source, charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * URL?
     * 
     * @param source
     * @return
     */
    public static String urlDecode(String source) {
        return urlDecode(source, "UTF-8");
    }

    /**
     * URL?
     * 
     * @param source
     * @return
     */
    public static String urlEncode(String source) {
        try {
            return URLEncoder.encode(source, "UTF-8").replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static String urlEncode(String source, String charset) {
        try {
            return URLEncoder.encode(source, charset).replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * ?Long
     * 
     * @param o
     * @param defaultValue
     * @return
     */
    public static long toLong(String o, Long defaultValue) {
        if (isBlank(o))
            return defaultValue;// ?nullnull
        try {
            return NumberUtils.createLong(o);
        } catch (NumberFormatException e) {
            if (defaultValue == null)// null?
                throw e;
            return defaultValue;
        }
    }

    /**
     * ?int
     * 
     * @param o
     * @param defaultValue
     * @return
     */
    public static int toInt(String o, Integer defaultValue) {
        if (isBlank(o))
            return defaultValue;// ?nullnull
        try {
            return Integer.valueOf(o);
        } catch (NumberFormatException e) {
            if (defaultValue == null)// null?
                throw e;
            return defaultValue;
        }
    }

    /**
     * ??float
     * 
     * @param o
     * @param defaultValue
     * @return
     */
    public static float toFloat(String o, Float defaultValue) {
        if (isBlank(o))
            return defaultValue;
        try {
            return NumberUtils.createFloat(o);
        } catch (NumberFormatException e) {
            if (defaultValue == null)// null?
                throw e;
            return defaultValue;
        }
    }

    /**
     * ??double
     * 
     * @param o
     * @param defaultValue
     * @return
     */
    public static double toDouble(String o, Double defaultValue) {
        if (isBlank(o))
            return defaultValue;
        try {
            return NumberUtils.createDouble(o);
        } catch (NumberFormatException e) {
            if (defaultValue == null)// null?
                throw e;
            return defaultValue;
        }
    }

    /**
     * 
     * 
     * @param a
     * @param b
     * @return
     */
    public static String toPercent(long a, long b) {
        return String.valueOf(10000 * a / b / 100f).concat("%");
    }

    /**
     * ?boolean??
     * 
     * @param s
     * @param defaultValue
     * @return
     */
    public static final boolean toBoolean(String s, Boolean defaultValue) {
        if ("true".equalsIgnoreCase(s) || "Y".equalsIgnoreCase(s) || "1".equals(s) || "ON".equalsIgnoreCase(s)
                || "yes".equalsIgnoreCase(s) || "T".equalsIgnoreCase(s)) {
            return true;
        }
        if ("false".equalsIgnoreCase(s) || "N".equalsIgnoreCase(s) || "0".equals(s) || "OFF".equalsIgnoreCase(s)
                || "no".equalsIgnoreCase(s) || "F".equalsIgnoreCase(s)) {
            return false;
        }
        if (defaultValue == null) {// ?????
            throw new IllegalArgumentException(s + "can't be cast to boolean.");
        }
        return defaultValue;
    }

    /**
     * ??????
     * 
     * @param fname
     * @param to
     * @return
     */
    public static String toFilename(String fname, String to) {
        StringBuilder sb = new StringBuilder();
        for (char c : fname.toCharArray()) {
            if (invalidCharsInFilename.indexOf(c) > -1) {
                sb.append(to);
            } else {
                sb.append(c);
            }
        }
        fname = sb.toString();
        if (fname.endsWith(".")) {
            fname = StringUtils.substringBeforeLast(fname, ".");
        }
        return fname;
    }

    /**
     * ?????0 convert number to String, add '0' before string.
     * 
     * @param number
     * @param length
     * @return
     */
    public static String toFixLengthString(int number, int length) {
        String a = String.valueOf(number);
        if (length > a.length()) {
            return repeat("0", length - a.length()) + a;
        } else {
            return a;
        }
    }

    /**
     * ??
     * 
     * @param number
     * @param length
     * @return
     */
    public static String toFixLengthString(String text, int length, boolean padOnLeft, char padChar) {
        if (text.length() == length) {
            return text;
        } else if (text.length() > length) {
            return text.substring(0, length);
        }
        StringBuilder sb = new StringBuilder(length);
        if (padOnLeft) {
            repeat(sb, padChar, length - text.length());
        }
        sb.append(text);
        if (!padOnLeft) {
            repeat(sb, padChar, length - text.length());
        }
        return sb.toString();
    }

    /**
     * ??
     * 
     * @param source
     *            ?
     * @param rev
     *            
     * @param keepSourceIfNotFound
     *            true??
     * @return
     */
    public static Substring stringRight(String source, String rev, boolean keepSourceIfNotFound) {
        if (source == null)
            return null;
        int n = source.indexOf(rev);
        if (n == -1) {
            if (keepSourceIfNotFound) {
                return new Substring(source);
            } else {
                return new Substring(source, source.length(), source.length());
            }
        }
        return new Substring(source, n + rev.length(), source.length());
    }

    /**
     * ?
     * 
     * @param source
     *            ?
     * @param rev
     *            
     * @param keepSourceIfNotFoundtrue?
     *            ?
     * @return
     */
    public static Substring stringLeft(String source, String rev, boolean keepSourceIfNotFound) {
        if (source == null)
            return null;
        int n = source.indexOf(rev);
        if (n == -1) {
            if (keepSourceIfNotFound) {
                return new Substring(source);
            } else {
                return new Substring(source, 0, 0);
            }
        }
        return new Substring(source, 0, n);
    }

    /**
     * ? substringAfter??substringAfter?
     * 
     * @param source
     * @param rev
     * @return
     */
    public static String substringAfterIfExist(String source, String rev) {
        if (source == null)
            return source;
        int n = source.indexOf(rev);
        if (n == -1)
            return source;
        return source.substring(n + rev.length());
    }

    /**
     * ?<br>
     * substringAfterLast??substringAfterLast?
     * 
     * @param source
     *            ?
     * @param keyword
     *            
     * @return
     */
    public static String substringAfterLastIfExist(String source, String keyword) {
        if (source == null)
            return source;
        int n = source.lastIndexOf(keyword);
        if (n == -1)
            return source;
        return source.substring(n + keyword.length());
    }

    /**
     * StringBuilder??Appendable???
     * 
     * @param sb
     *            ?
     * @param str
     *            ???
     * @param n
     *            ??
     */
    public static void repeat(Appendable sb, CharSequence str, int n) {
        if (n <= 0)
            return;
        try {
            for (int i = 0; i < n; i++) {
                sb.append(str);
            }
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * StringBuilder??Appendable???
     * 
     * @param sb
     *            ?
     * @param str
     *            ?
     * @param n
     *            ???0??
     */
    public static void repeat(Appendable sb, char str, int n) {
        if (n <= 0)
            return;
        try {
            for (int i = 0; i < n; i++) {
                sb.append(str);
            }
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * ??repeat the string for n times.
     * 
     * @param str
     *            String to repeat
     * @param n
     *            repeat times.
     * @return
     */
    public static String repeat(CharSequence str, int n) {
        if (n <= 0)
            return "";
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < n; i++) {
            s.append(str);
        }
        return s.toString();
    }

    /**
     * ??
     * 
     * @param c
     * @param n
     * @return
     */
    public static String repeat(char c, int n) {
        if (n <= 0)
            return "";
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < n; i++) {
            s.append(c);
        }
        return s.toString();
    }

    // //////////HTML?
    private static final String htmlEscEntities = " <>&\"'\u00A9\u00AE";
    private static final String htmlEscapeSequence[] = { "&nbsp;", "&lt;", "&gt;", "&amp;", "&quot;", "&acute;",
            "&copy;", "&reg;" };

    /**
     * HTML
     */
    public static CharSequence escapeHtml(CharSequence s, boolean unicode) {
        if (unicode)
            return StringEscapeUtils.escapeHtml(s.toString());
        StringBuilder sb = new StringBuilder(s.length() + 16);
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            int n = htmlEscEntities.indexOf(c);
            if (n > -1) {
                sb.append(htmlEscapeSequence[n]);
            } else {
                sb.append(c);
            }
        }
        return sb.length() == s.length() ? s : sb.toString();// ??string?
    }

    /**
     * HTML
     * 
     * @param s
     * @return
     */
    public static CharSequence escapeHtml(CharSequence s) {
        return escapeHtml(s, false);
    }

    /**
     * HTML??
     * 
     * @param s
     * @return
     */
    public static String unescapeHtml(String s) {
        return StringEscapeUtils.unescapeHtml(s);
    }

    /**
     * HTML?? HTML?HTML ?: '?'
     * ??SQL?
     */
    public static String unescapeHtmlToSql(String s) {
        if (s == null)
            return null;
        return StringEscapeUtils.escapeSql(StringEscapeUtils.unescapeHtml(s));
    }

    /**
     * ?,Apache commons??
     * 
     * @param arg1
     * @param arg2
     * @param arg3
     * @return
     */
    public static String substringBetween(String arg1, String arg2, String arg3) {
        int a = arg1.indexOf(arg2);
        int b = arg1.lastIndexOf(arg3);
        if (a == -1 || b == -1)
            return "";
        if (a == b)
            return "";
        if (a > b)
            return "";
        return arg1.substring(a + arg2.length(), b);
    }

    /**
     * ?? ?*?????01
     * 
     * @param s
     * @param key
     * @param IgnoreCase
     * @return
     */
    public static boolean contains(String s, String key, boolean IgnoreCase) {
        return matches(s, key, IgnoreCase, false, false, false);
    }

    /**
     * String?? ?String.matches?? 
     * *????0~1?+?1? ??
     * Windows??
     */
    public static boolean matches(String s, String key, boolean IgnoreCase) {
        return matches(s, key, IgnoreCase, true, true, false);
    }

    /**
     * String?? ?String.matches?? 
     * *????0~1?+?1? ??
     * Windows??
     * 
     * @param IgnoreCase
     *            ?
     * @param matchStart
     *            ????
     * @param matchEnd
     *            ????
     * @param wildcardSpace
     *            ????\n\t
     * @return
     */
    public static boolean matches(String s, String key, boolean IgnoreCase, boolean matchStart, boolean matchEnd,
            boolean wildcardSpace) {
        if (s == null && key == null)
            throw new NullPointerException();
        if (s == null)
            return false;
        if (key == null)
            return true;
        if (IgnoreCase) {
            s = s.toUpperCase();
        }
        Pattern p = RegexpUtils.simplePattern(key, IgnoreCase, matchStart, matchEnd, wildcardSpace);
        return p.matcher(s).matches();
    }

    private static DecimalFormat floatFormat = new DecimalFormat("#0.00");

    /**
     * ????
     * 
     * @param number
     * @return
     */
    public static final String formatFloat(float number) {
        return floatFormat.format(number);
    }

    /**
     * ??
     * 
     * @param num
     * @param template
     * @return
     */
    public static final String formatNumber(Number num, String template) {
        DecimalFormat f = new DecimalFormat(template);
        return f.format(num);
    }

    /**
     * 
     */
    public static final String ltrim(String s) {
        int len = s.length();
        int st = 0;
        int off = 0; /* avoid getfield opcode */
        char[] val = s.toCharArray(); /* avoid getfield opcode */
        while ((st < len) && (val[off + st] <= ' ')) {
            st++;
        }
        return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s;
    }

    /**
     * 
     * 
     * @param s
     * @param trimChars
     * @return
     */
    public static final String ltrim(String s, char... trimChars) {
        int len = s.length();
        int st = 0;
        int off = 0;
        while ((st < len) && (ArrayUtils.contains(trimChars, s.charAt(off + st)))) {
            st++;
        }
        return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s;
    }

    /**
     * ?
     * 
     * @param s
     * @param trimChars
     * @return
     */
    public static final String rtrim(String s, char... trimChars) {
        int len = s.length();
        int st = 0;
        int off = 0; /* avoid getfield opcode */
        while ((st < len) && ArrayUtils.contains(trimChars, s.charAt(off + len - 1))) {
            len--;
        }
        return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s;
    }

    /**
     * ?
     * 
     * @param s
     * @return
     */
    public static final String rtrim(String s) {
        int len = s.length();
        int st = 0;
        int off = 0; /* avoid getfield opcode */
        char[] val = s.toCharArray(); /* avoid getfield opcode */
        while ((st < len) && (val[off + len - 1] <= ' ')) {
            len--;
        }
        return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s;
    }

    /**
     * ????trim
     * 
     * @param s
     * @param lTrimChars
     *            ?trim
     * @param rTrimChars
     *            ??trim
     * @return
     */
    public static final String lrtrim(String s, char[] lTrimChars, char[] rTrimChars) {
        int len = s.length();
        int st = 0;
        int off = 0;
        while ((st < len) && (ArrayUtils.contains(lTrimChars, s.charAt(off + st)))) {
            st++;
        }
        while ((st < len) && ArrayUtils.contains(rTrimChars, s.charAt(off + len - 1))) {
            len--;
        }
        return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s;
    }

    /**
     * 8??
     * 
     * @return
     */
    public static final String randomString() {
        return RandomStringUtils.randomNumeric(8);
    }

    /**
     * 32?Hex uuid(36)
     */
    public static final String generateGuid() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString();
    }

    /**
     * CRC?,8???
     */
    public static String getCRC(InputStream in) {
        CRC32 crc32 = new CRC32();
        byte[] b = new byte[65536];
        int len = 0;
        try {
            while ((len = in.read(b)) != -1) {
                crc32.update(b, 0, len);
            }
            return Long.toHexString(crc32.getValue());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    /**
     * CRC?,8???
     */
    public static String getCRC(String s) {
        ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes());
        return getCRC(in);
    }

    /**
     * MD5?,
     * 
     * @param s
     *            
     * @return 32???MD5
     */
    public final static String getMD5(String s) {
        ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes());
        byte[] md = hash(in, "MD5");
        return join(md, (char) 0, 0, md.length);
    }

    /**
     * MD5?
     * 
     * @param in
     * @return 32???MD5
     */
    public final static String getMD5(InputStream in) {
        byte[] md = hash(in, "MD5");
        return join(md, (char) 0, 0, md.length);
    }

    /**
     * SHA-1
     * 
     * @param s
     * @return
     */
    public final static String getSHA1(String s) {
        ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes());
        byte[] md = hash(in, "SHA-1");
        return join(md, (char) 0, 0, md.length);
    }

    /**
     * SHA256
     * 
     * @param s
     * @return
     */
    public final static String getSHA256(String s) {
        ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes());
        byte[] md = hash(in, "SHA-256");
        return join(md, (char) 0, 0, md.length);
    }

    /**
     * SHA-1?
     * 
     * @param in
     * @return
     */
    public final static String getSHA1(InputStream in) {
        byte[] md = hash(in, "SHA-1");
        return join(md, (char) 0, 0, md.length);
    }

    private static final char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
            'E', 'F' };

    /**
     * byte?????Integer.toHexString?JDK3?,
     * 
     * 
     * @see jef.tools.ByteUtils#hex2byte(CharSequence, boolean) ? (hex2byte)
     */
    public static String byte2hex(byte[] b) {
        return join(b, ' ', 0, b.length);
    }

    /**
     * byte????
     * 
     * @param b
     * @param offset
     * @param len
     * @return
     * @see jef.tools.ByteUtils#hex2byte(CharSequence, boolean) ? (hex2byte)
     */
    public static String byte2hex(byte[] b, int offset, int len) {
        return join(b, ' ', offset, len);
    }

    /*
     * ??
     */
    public final static byte[] hash(InputStream in, String algorithm) {
        try {
            MessageDigest mdTemp = MessageDigest.getInstance(algorithm);
            byte[] b = new byte[4096];
            int len = 0;
            while ((len = in.read(b)) != -1) {
                mdTemp.update(b, 0, len);
            }
            return mdTemp.digest();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    /** ? */
    public static String getTimeStamp() {
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     * ??
     * 
     * @param line
     * @return ?
     */
    public static int ignoreWhiteSpace(String line) {
        int inLength = line.length();
        int beginPos = 0;
        for (; beginPos < inLength; beginPos++) {
            if (!Character.isWhitespace(line.charAt(beginPos))) {
                break;
            }
        }
        return beginPos;
    }

    /**
     * ???
     * 
     * @param line
     * @return ???
     */
    public static int ignoreRightWhiteSpace(String line) {
        int beginPos = line.length() - 1;
        for (; beginPos >= 0; beginPos--) {
            if (!Character.isWhitespace(line.charAt(beginPos))) {
                break;
            }
        }
        return beginPos + 1;
    }

    /**
     * ?
     * 
     * @param s
     * @return
     */
    public static int countAsian(String s) {
        int n = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c > 255 && c != 65279) {
                n++;
            }
        }
        return n;
    }

    /**
     * ?
     * 
     * @param s
     * @return
     */
    public static boolean hasAsian(String s) {
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c > 255 && c != 65279) {
                return true;
            }
        }
        return false;
    }

    /**
     * 
     * 
     * @param obj
     * @return
     */
    public static String toString(Object obj) {
        if (obj == null)
            return EMPTY;
        return obj.toString();
    }

    /**
     * ???
     * 
     * @return
     */
    public static Substring subLeftWithChar(String ss, char[] chars) {
        int n = ss.length();
        for (int i = 0; i < ss.length(); i++) {
            char c = ss.charAt(i);
            if (!ArrayUtils.contains(chars, c)) {
                n = i;
                break;
            }
        }
        return new Substring(ss, 0, n);
    }

    /**
     * ?????
     * 
     * @return
     */
    public static Substring subRightWithChar(String ss, char[] chars) {
        int n = 0;
        for (int i = ss.length() - 1; i >= 0; i--) {
            char c = ss.charAt(i);
            if (!ArrayUtils.contains(chars, c)) {
                n = i + 1;
                break;
            }
        }
        return new Substring(ss, n, ss.length());
    }

    /**
     * ??
     * 
     * @param unknown
     * @param tokens
     * @return
     */
    public static String[] splitOfAny(String unknown, char[] tokens) {
        List<String> list = new ArrayList<String>();
        StringSpliter sp = new StringSpliter(unknown);
        while (sp.setKeyOfAny(tokens)) {
            list.add(sp.getLeft().toString());
            sp = new StringSpliter(sp.getRight());
        }
        list.add(sp.getSource().toString());
        return list.toArray(new String[list.size()]);
    }

    /**
     * ??
     * 
     * @param unknown
     * @param tokens
     * @return
     */
    public static String[] splitOfAny(String unknown, String[] tokens) {
        List<String> list = new ArrayList<String>();
        StringSpliter sp = new StringSpliter(unknown);
        while (sp.setKeyOfAny(tokens)) {
            list.add(sp.getLeft().toString());
            sp = new StringSpliter(sp.getRight());
        }
        list.add(sp.getSource().toString());
        return list.toArray(new String[list.size()]);
    }

    /**
     * ?
     * 
     * @param b
     * @param c
     * @return
     */
    public static String join(byte[] b, char c) {
        if (b == null)
            return "";
        return join(b, c, 0, b.length);
    }

    /**
     * ?
     * 
     * @param b
     * @param dchar
     * @return
     */
    public static String join(byte[] b, char dchar, int offset, int len) {
        if (b == null || b.length == 0)
            return "";
        boolean appendSpace = (dchar != 0);
        int j = offset + len;
        if (j > b.length)
            j = b.length; // ?
        char str[] = new char[j * ((appendSpace) ? 3 : 2)];
        int k = 0;
        for (int i = offset; i < j; i++) {
            byte byte0 = b[i];
            str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // >>?? >>>??
            str[k++] = hexDigits[byte0 & 0xf];
            if (appendSpace)
                str[k++] = dchar;
        }
        if (appendSpace) {
            return new String(str, 0, k - 1);
        } else {
            return new String(str);
        }
    }

    /**
     * ?
     * 
     * @param array
     *            ?
     * @param separator
     *            
     * @return
     */
    public static String join(int[] array, String separator) {
        StringBuilder sb = new StringBuilder();
        if (array != null && array.length > 0) {
            int n = 0;
            sb.append(array[n++]);
            while (n < array.length) {
                sb.append(separator);
                sb.append(array[n++]);
            }
        }
        return sb.toString();
    }

    /**
     * ?
     * 
     * @param array
     *            ?
     * @param separator
     *            
     * @return
     */
    public static String join(float[] array, String separator) {
        StringBuilder sb = new StringBuilder();
        if (array != null && array.length > 0) {
            int n = 0;
            sb.append(array[n++]);
            while (n < array.length) {
                sb.append(separator);
                sb.append(array[n++]);
            }
        }
        return sb.toString();
    }

    /**
     * ?
     * 
     * @param array
     *            ?
     * @param separator
     *            
     * @return
     */
    public static String join(double[] array, String separator) {
        StringBuilder sb = new StringBuilder();
        if (array != null && array.length > 0) {
            int n = 0;
            sb.append(array[n++]);
            while (n < array.length) {
                sb.append(separator);
                sb.append(array[n++]);
            }
        }
        return sb.toString();
    }

    /**
     * 
     * 
     * @param array
     *            ?
     * @param separator
     *            
     * @return
     */
    public static String join(boolean[] array, String separator) {
        StringBuilder sb = new StringBuilder();
        if (array != null && array.length > 0) {
            int n = 0;
            sb.append(array[n++]);
            while (n < array.length) {
                sb.append(separator);
                sb.append(array[n++]);
            }
        }
        return sb.toString();
    }

    /**
     * ?
     * 
     * @param array
     *            ?
     * @param separator
     *            
     * @return
     */
    public static String join(long[] array, String separator) {
        StringBuilder sb = new StringBuilder();
        if (array != null && array.length > 0) {
            int n = 0;
            sb.append(array[n++]);
            while (n < array.length) {
                sb.append(separator);
                sb.append(array[n++]);
            }
        }
        return sb.toString();
    }

    /**
     * ?
     * 
     * @param array
     *            ?
     * @param separator
     *            
     * @return
     */
    public static String join(short[] array, String separator) {
        StringBuilder sb = new StringBuilder();
        if (array != null && array.length > 0) {
            int n = 0;
            sb.append(array[n++]);
            while (n < array.length) {
                sb.append(separator);
                sb.append(array[n++]);
            }
        }
        return sb.toString();
    }

    /**
     * ?
     * 
     * @param array
     *            ?
     * @param separator
     *            
     * @return
     */
    public static String join(char[] array, String separator) {
        int len = array == null ? 0 : array.length;
        StringBuilder sb = new StringBuilder(len + separator.length() * (len - 1));
        if (len > 0) {
            int n = 0;
            sb.append(array[n++]);
            while (n < array.length) {
                sb.append(separator);
                sb.append(array[n++]);
            }
        }
        return sb.toString();
    }

    /**
     * ?
     * 
     * @param ss
     * @param sep
     * @return
     */
    public static String join(Object[] os, String separator) {
        if (os == null || os.length == 0)
            return EMPTY;
        String[] ss = new String[os.length];
        int len = 0;
        int sepLen = separator.length();
        for (int i = 0; i < os.length; i++) {
            Object o = os[i];
            ss[i] = o == null ? "" : o.toString();
            len += ss[i].length();
            len += sepLen;
        }
        StringBuilder sb = new StringBuilder(len - sepLen);
        int n = 0;
        sb.append(ss[n++]);
        while (n < ss.length) {
            sb.append(separator);
            sb.append(ss[n++]);
        }
        return sb.toString();
    }

    /**
     * ?$[key}properties
     * 
     * @param s
     * @param prop
     * @return
     */
    public static String convertProperty(String s, Properties prop) {
        int i = s.indexOf("${");
        if (i > -1) {
            StringBuilder sb = new StringBuilder();
            int j = -1;
            while (i > -1) {
                sb.append(s.subSequence(j + 1, i));
                j = s.indexOf('}', i + 1);
                String key = "";
                if (j > 0) {// Invalid block
                    key = s.substring(i + 2, j);
                } else {
                    j = s.indexOf("${", i + 2) - 1;// 
                    if (j < 0) {
                        j = s.length() - 1;
                    }
                }
                if (StringUtils.isEmpty(key)) {
                    sb.append(s.subSequence(i, j + 1));// J
                } else {
                    String value = prop.getProperty(key);
                    if (value != null)
                        sb.append(value);
                }
                i = s.indexOf("${", j);
            }
            sb.append(s.substring(j + 1));
            return sb.toString();
        }
        return s;

    }

    /**
     * ? ?obj isArray??Join
     * 
     * @Title: join @param ? @return String  @throws
     */
    public static String join(Object obj, String dchar) {
        Assert.notNull(obj);
        if (!obj.getClass().isArray()) {
            throw new IllegalArgumentException("The input object to join must be a Array and not null.");
        }
        Class<?> priType = obj.getClass().getComponentType();
        if (priType == Boolean.TYPE) {
            return join((boolean[]) obj, dchar);
        } else if (priType == Byte.TYPE) {
            return join((byte[]) obj, dchar);
        } else if (priType == Character.TYPE) {
            return join((char[]) obj, dchar);
        } else if (priType == Integer.TYPE) {
            return join((int[]) obj, dchar);
        } else if (priType == Long.TYPE) {
            return join((long[]) obj, dchar);
        } else if (priType == Float.TYPE) {
            return join((float[]) obj, dchar);
        } else if (priType == Double.TYPE) {
            return join((double[]) obj, dchar);
        } else if (priType == Short.TYPE) {
            return join((short[]) obj, dchar);
        } else {
            return join((Object[]) obj, dchar);
        }
    }

    private static final double SIZE_1K = 1024;
    private static final double SIZE_1M = 1048576;
    private static final double SIZE_1G = 1073741824;

    /**
     * ???xxG xxM?
     * 
     * @param size
     * @return
     */
    public static String formatSize(long size) {
        DecimalFormat df = new DecimalFormat("#.##");
        if (size < SIZE_1K) {
            return String.valueOf(size);
        } else if (size < SIZE_1M) {
            return df.format(size / SIZE_1K).concat("K");
        } else if (size < SIZE_1G) {
            return df.format(size / SIZE_1M).concat("M");
        } else {
            return df.format(size / SIZE_1G).concat("G");
        }
    }

    /**
     * ?
     * 
     * @param source
     * @param n
     * @param str
     * @return
     */
    public static String insert(String source, int n, String str) {
        if (source.length() <= n)
            return source.concat(str);
        if (n < 0)
            n = 0;
        StringBuilder sb = new StringBuilder(source.length() + str.length());
        sb.append(source, 0, n);
        sb.append(str);
        sb.append(source, n, source.length());
        return sb.toString();
    }

    /**
     * 
     * 
     * @param str
     * @param maxLength
     * @param append
     *            ??
     * @return
     */
    public static String truncate(String str, int maxLength, String... append) {
        if (str.length() <= maxLength)
            return str;
        str = str.substring(0, maxLength);
        if (append.length > 0) {
            return str.concat(append[0]);
        } else {
            return str;
        }
    }

    /**
     * str1str2str1??str2,null
     * 
     * @param str1
     * @param str2
     * @return
     */
    public static String removeOnce(String str1, String str2) {
        int n = str1.indexOf(str2);
        if (n == -1)
            return null;
        if (n == 0) {
            return str1.substring(n + str2.length());
        } else if (n + str2.length() == str1.length()) {
            return str1.substring(0, n);
        } else {
            return str1.substring(0, n).concat(str1.substring(n + str2.length()));
        }
    }

    /**
     * ???
     * 
     * @Title: isNumericOrMinus @param isFloat ??? @return boolean
     *          @throws
     */
    public static boolean isNumericOrMinus(String str, boolean isFloat) {
        if (str == null)
            return false;
        int sz = str.length();
        if (sz == 0)
            return false;
        short hasPoint = 0;
        short start = 0;
        if (str.charAt(0) == '-')
            start = 1;
        for (int i = start; i < sz; i++) {
            char c = str.charAt(i);
            if (!Character.isDigit(c)) {
                if (c == '.' && hasPoint == 0 && isFloat) {
                    hasPoint = 1;
                } else {
                    return false;
                }
            }
        }
        return (sz - start) > hasPoint;
    }

    /**
     * ?String,?3String.concat
     * 55String?concat?
     * 
     * @param args
     * @return
     */
    public final static String concat(String... args) {
        if (args.length == 1)
            return args[0];
        int n = 0;
        for (String s : args) {
            if (s == null)
                continue;
            n += s.length();
        }
        StringBuilder sb = new StringBuilder(n);
        for (String s : args) {
            if (s == null)
                continue;
            sb.append(s);
        }
        return sb.toString();
    }

    /**
     * ????
     * 
     * @param str
     * @return
     */
    public static boolean isValidNumer(String str) {
        return isNumericOrMinus(str, true);
    }

    /**
     * ????a-f A-F 0-9
     * 
     * @param str
     * @return
     */
    public static boolean isHexString(String str) {
        int len = str.length();
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            if (c < 48 || (c > 57 && c < 65) || (c > 70 && c < 97) || c > 102) {
                return false;
            }
        }
        return true;
    }

    /**
     * ????
     * 
     * @param str
     * @return
     */
    public static boolean isNumericOrMinus(String str) {
        return isNumericOrMinus(str, false);
    }

    /**
     * ??toString?
     * 
     * @param value
     * @return
     */
    public static boolean isNotEmpty(Object value) {
        return !isEmpty(value);
    }

    /**
     * ?toString?
     * 
     * @param value
     * @return
     */
    public static boolean isEmpty(Object value) {
        if (value == null)
            return true;
        if (value instanceof CharSequence) {
            return ((CharSequence) value).length() == 0;
        }
        return false;
    }

    /**
     * key2
     * 
     * @param source
     * @param key
     * @return
     */
    public static String[] splitLast(String source, String key) {
        if (source == null)
            return null;
        int n = source.lastIndexOf(key);
        if (n < 0)
            return new String[] { source, "" };
        return new String[] { source.substring(0, n), source.substring(n + key.length()) };
    }

    /**
     * ?
     * 
     * @param source
     * @param key
     * @return
     */
    public static String[] splitLast(String source, char key) {
        if (source == null)
            return null;
        int n = source.lastIndexOf(key);
        if (n < 0)
            return new String[] { source, "" };
        return new String[] { source.substring(0, n), source.substring(n + 1) };
    }

    /**
     * ?Key/Value 
     * 
     * @param source
     *            ??
     * @param entrySep
     *            entry
     * @param keyValueSep
     *            key/value
     * @param keyUpper
     *            key?0? -1? 1
     * 
     * @return
     */
    public static Map<String, String> toMap(String source, String entrySep, String keyValueSep, int keyUpper) {
        Map<String, String> result = new LinkedHashMap<String, String>();
        if (source != null) {
            for (String entry : StringUtils.split(source, entrySep)) {
                entry = entry.trim();
                int index = entry.indexOf(keyValueSep);
                if (index > -1) {
                    String key = entry.substring(0, index).trim();
                    if (keyUpper > 0) {
                        key = key.toUpperCase();
                    } else if (keyUpper < 0) {
                        key = key.toLowerCase();
                    }
                    result.put(key, entry.substring(index + 1).trim());
                } else {
                    String key = entry;
                    if (keyUpper > 0) {
                        key = key.toUpperCase();
                    } else if (keyUpper < 0) {
                        key = key.toLowerCase();
                    }
                    result.put(key, "");
                }
            }
        }
        return result;
    }

    /**
     * {@link #toMap}?mapstring
     * 
     * @param map
     * @param entrySep
     * @param keyValueSep
     * @return
     */
    public static String toString(Map<String, String> map, String entrySep, String keyValueSep) {
        StringBuilder sb = new StringBuilder();
        Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
        if (iter.hasNext()) {
            {
                Map.Entry<String, String> e = iter.next();
                sb.append(e.getKey()).append(keyValueSep).append(e.getValue());
            }
            for (; iter.hasNext();) {
                Map.Entry<String, String> e = iter.next();
                sb.append(entrySep).append(e.getKey()).append(keyValueSep).append(e.getValue());
            }
        }
        return sb.toString();
    }

    /**
     * 
     * 
     * @param str
     * @param searchChars
     * @param startPos
     * @return
     */
    public static int indexOfAny(String str, char[] searchChars, int startPos) {
        if (isEmpty(str) || ArrayUtils.isEmpty(searchChars)) {
            return -1;
        }
        for (int i = startPos; i < str.length(); i++) {
            char ch = str.charAt(i);
            for (int j = 0; j < searchChars.length; j++) {
                if (searchChars[j] == ch) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * ?????
     * 
     * @param str
     *            ?
     * @param searchChars
     *            ??
     * @param startPos
     *            ?
     * @return
     */
    public static int lastIndexOfAny(String str, char[] searchChars, int startPos) {
        if ((str == null) || (searchChars == null)) {
            return -1;
        }
        if (startPos < 0) {
            startPos = 0;
        }
        for (int i = str.length() - 1; i >= startPos; i--) {
            char c = str.charAt(i);
            for (int j = 0; j < searchChars.length; j++) {
                if (c == searchChars[j]) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 
     * 
     * @param data
     *            ?
     * @param sep
     *            
     * @param sb
     *            
     */
    public static void joinTo(Collection<?> data, String sep, StringBuilder sb) {
        if (data == null || data.isEmpty())
            return;
        Iterator<?> iterator = data.iterator();
        sb.append(String.valueOf(iterator.next()));
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            sb.append(sep).append(String.valueOf(obj));
        }
    }

    /**
     * 
     * 
     * @param data
     *            ?
     * @param sep
     *            
     * @param sb
     *            
     */
    public static void joinTo(Object[] data, char sep, StringBuilder sb) {
        if (data == null || data.length == 0)
            return;
        sb.append(String.valueOf(data[0]));
        for (int i = 1; i < data.length; i++) {
            sb.append(sep).append(String.valueOf(data[i]));
        }
    }

    /**
     * ???
     * 
     * @param content
     * @return
     */
    public static String replaceTextByJvmArg(String content) {
        StringBuffer result = new StringBuffer();
        Properties p = System.getProperties();
        int pos = 0;
        int indexStart = -1;
        int indexEnd = -1;
        String jmvParam = null;
        String jmvVal = null;
        do {
            indexStart = content.indexOf("${", pos);
            if (indexStart > 0) {
                indexEnd = content.indexOf("}");
                if (indexEnd < 0)
                    throw new IllegalArgumentException(
                            "tag ${ and }  should appear in pair, ${ existed, but } can't find");
            } else {
                indexEnd = -1;
            }
            if (indexStart != -1 && indexEnd != -1) {
                jmvParam = content.substring(indexStart + 2, indexEnd);
                jmvVal = p.getProperty(jmvParam);
                result.append(content.substring(pos, indexStart));
                if (jmvVal != null) {
                    result.append(jmvVal);
                } else {
                    throw new IllegalArgumentException(
                            "argument ${" + jmvParam + "} can't be found in jvm argument");
                }
            } else {
                result.append(content.substring(pos));
            }
            pos = indexEnd + 1;
        } while (pos > 0);
        return result.toString();
    }

    /**
     * ??hashcode
     * 
     * @param text
     * @return
     */
    public static int lowerHashCode(String text) {
        if (text == null) {
            return 0;
        }
        // return text.toLowerCase().hashCode();
        int h = 0;
        for (int i = 0; i < text.length(); ++i) {
            char ch = text.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                ch = (char) (ch + 32);
            }

            h = 31 * h + ch;
        }
        return h;
    }

    /**
     * ?int
     * 
     * @param text
     *            
     * @param dem
     *            
     * @param defaultValue
     *            ???
     * @return 
     */
    public static int[] toIntArray(String text, char dem, int defaultValue) {
        String[] ss = StringUtils.split(text, dem);
        int[] result = new int[ss.length];
        for (int i = 0; i < ss.length; i++) {
            String s = ss[i];
            if (s.length() > 0) {
                try {
                    int value = Integer.valueOf(s.trim());
                    result[i] = value;
                } catch (NumberFormatException e) {
                    result[i] = defaultValue;
                }
            }
        }
        return result;
    }

    /**
     * ?int??
     * 
     * @param text
     *            
     * @param dem
     *            
     * @return 
     */
    public static int[] toIntArray(String text, char dem) {
        String[] ss = StringUtils.split(text, dem);
        IntList result = new IntList();
        for (int i = 0; i < ss.length; i++) {
            String s = ss[i].trim();
            if (s.length() > 0) {
                try {
                    int value = Integer.parseInt(s.trim());
                    result.add(value);
                } catch (NumberFormatException e) {
                }
            }
        }
        return result.toArrayUnsafe();
    }

    /**
     * ?float
     * 
     * @param text
     *            
     * @param dem
     *            
     * @return 
     */
    public static float[] toFloatArray(String text, char dem) {
        String[] ss = StringUtils.split(text, dem);
        FloatList result = new FloatList();
        for (int i = 0; i < ss.length; i++) {
            String s = ss[i].trim();
            if (s.length() > 0) {
                try {
                    float value = Float.parseFloat(s.trim());
                    result.add(value);
                } catch (NumberFormatException e) {
                }
            }
        }
        return result.toArrayUnsafe();
    }

    /**
     * ?long
     * 
     * @param text
     *            
     * @param dem
     *            
     * @return 
     */
    public static long[] toLongArray(String text, char dem) {
        String[] ss = StringUtils.split(text, dem);
        LongList result = new LongList();
        for (int i = 0; i < ss.length; i++) {
            String s = ss[i].trim();
            if (s.length() > 0) {
                try {
                    long value = Long.parseLong(s.trim());
                    result.add(value);
                } catch (NumberFormatException e) {
                }
            }
        }
        return result.toArrayUnsafe();
    }

    /**
     * ?double
     * 
     * @param text
     *            
     * @param dem
     *            
     * @return 
     */
    public static double[] toDoubleArray(String text, char dem) {
        String[] ss = StringUtils.split(text, dem);
        DoubleList result = new DoubleList();
        for (int i = 0; i < ss.length; i++) {
            String s = ss[i].trim();
            if (s.length() > 0) {
                try {
                    double value = Double.parseDouble(s.trim());
                    result.add(value);
                } catch (NumberFormatException e) {
                }
            }
        }
        return result.toArrayUnsafe();
    }

    /**
     * ?double
     * 
     * @param text
     *            
     * @param dem
     *            
     * @return 
     */
    public static boolean[] toBooleanArray(String text, char dem) {
        String[] ss = StringUtils.split(text, dem);
        BooleanList result = new BooleanList();
        for (int i = 0; i < ss.length; i++) {
            String s = ss[i].trim();
            if (s.length() > 0) {
                try {
                    boolean value = toBoolean(s.trim(), null);
                    result.add(value);
                } catch (IllegalArgumentException e) {
                }
            }
        }
        return result.toArrayUnsafe();
    }

    /**
     * ?Date
     * 
     * @param text
     * @param dem
     * @param df
     * @return
     */
    public static Date[] toDateArray(String text, char dem, DateFormat df) {
        String[] ss = StringUtils.split(text, dem);
        List<Date> list = new ArrayList<Date>();
        for (int i = 0; i < ss.length; i++) {
            String s = ss[i].trim();
            if (s.length() > 0) {
                try {
                    list.add(df.parse(s));
                } catch (ParseException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        }
        return list.toArray(new Date[list.size()]);
    }

    /**
     * Tokenize the given String into a String array via a StringTokenizer.
     * Trims tokens and omits empty tokens.
     * <p>
     * The given delimiters string is supposed to consist of any number of
     * delimiter characters. Each of those characters can be used to separate
     * tokens. A delimiter is always a single character; for multi-character
     * delimiters, consider using {@code delimitedListToStringArray}
     * 
     * @param str
     *            the String to tokenize
     * @param delimiters
     *            the delimiter characters, assembled as String (each of those
     *            characters is individually considered as delimiter).
     * @return an array of the tokens
     * @see java.util.StringTokenizer
     * @see String#trim()
     * @see #delimitedListToStringArray
     */
    public static String[] tokenizeToStringArray(String str, String delimiters) {
        return tokenizeToStringArray(str, delimiters, true, true);
    }

    /**
     * Tokenize the given String into a String array via a StringTokenizer.
     * <p>
     * The given delimiters string is supposed to consist of any number of
     * delimiter characters. Each of those characters can be used to separate
     * tokens. A delimiter is always a single character; for multi-character
     * delimiters, consider using {@code delimitedListToStringArray}
     * 
     * @param str
     *            the String to tokenize
     * @param delimiters
     *            the delimiter characters, assembled as String (each of those
     *            characters is individually considered as delimiter)
     * @param trimTokens
     *            trim the tokens via String's {@code trim}
     * @param ignoreEmptyTokens
     *            omit empty tokens from the result array (only applies to
     *            tokens that are empty after trimming; StringTokenizer will not
     *            consider subsequent delimiters as token in the first place).
     * @return an array of the tokens ({@code null} if the input String was
     *         {@code null})
     * @see java.util.StringTokenizer
     * @see String#trim()
     * @see #delimitedListToStringArray
     */
    public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens,
            boolean ignoreEmptyTokens) {

        if (str == null) {
            return null;
        }
        StringTokenizer st = new StringTokenizer(str, delimiters);
        List<String> tokens = new ArrayList<String>();
        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            if (trimTokens) {
                token = token.trim();
            }
            if (!ignoreEmptyTokens || token.length() > 0) {
                tokens.add(token);
            }
        }
        return toStringArray(tokens);
    }

    /**
     * Copy the given Collection into a String array. The Collection must
     * contain String elements only.
     * <p/>
     * <p>
     * Copied from the Spring Framework while retaining all license, copyright
     * and author information.
     * 
     * @param collection
     *            the Collection to copy
     * @return the String array (<code>null</code> if the passed-in Collection
     *         was <code>null</code>)
     */
    public static String[] toStringArray(Collection<?> collection) {
        if (collection == null) {
            return null;
        }
        return (String[]) collection.toArray(new String[collection.size()]);
    }

    /**
     * Determines whether or not the sting 'searchIn' contains the string
     * 'searchFor', disregarding case and leading whitespace
     * 
     * @param searchIn
     *            the string to search in
     * @param searchFor
     *            the string to search for
     * 
     * @return true if the string starts with 'searchFor' ignoring whitespace
     */
    public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor) {
        return startsWithIgnoreCaseAndWs(searchIn, searchFor, 0);
    }

    /**
     * Determines whether or not the sting 'searchIn' contains the string
     * 'searchFor', disregarding case and leading whitespace
     * 
     * @param searchIn
     *            the string to search in
     * @param searchFor
     *            the string to search for
     * @param beginPos
     *            where to start searching
     * 
     * @return true if the string starts with 'searchFor' ignoring whitespace
     */
    public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor, int beginPos) {
        if (searchIn == null) {
            return searchFor == null;
        }

        int inLength = searchIn.length();

        for (; beginPos < inLength; beginPos++) {
            if (!Character.isWhitespace(searchIn.charAt(beginPos))) {
                break;
            }
        }

        return startsWithIgnoreCase(searchIn, beginPos, searchFor);
    }

    /**
     * Determines whether or not the string 'searchIn' contains the string
     * 'searchFor', dis-regarding case starting at 'startAt' Shorthand for a
     * String.regionMatch(...)
     * 
     * @param searchIn
     *            the string to search in
     * @param startAt
     *            the position to start at
     * @param searchFor
     *            the string to search for
     * 
     * @return whether searchIn starts with searchFor, ignoring case
     */
    public static boolean startsWithIgnoreCase(String searchIn, int startAt, String searchFor) {
        return searchIn.regionMatches(true, startAt, searchFor, 0, searchFor.length());
    }
}