package com.energy.manage.common.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.CaseFormat;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符串实用工具类
 */
public class StringTools {

  public static final String EMPTY = "";

  public static String COMMA_SEPARATOR = ",";
  /**
   * Constant representing the default delimiter character (comma), equal to <code>','</code>
   */
  public static final char DEFAULT_DELIMITER_CHAR = ',';

  /**
   * Constant representing the default quote character (double quote), equal to '&quot;'</code>
   */
  public static final char DEFAULT_QUOTE_CHAR = '"';

  private static final char SEPARATOR = '_';

  /**
   * 判断一个字符串对象是否是""或null
   *
   * @param str 要判断的字符串对象
   * @return
   */
  public static boolean isEmpty(String str) {
    return StringUtils.isEmpty(str);
  }

  public static boolean isEmpty(Object obj) {
    boolean flag = false;
    if (obj == null) {
      flag = true;
    }
    return flag;
  }

  public static boolean isNotEmpty(Object obj) {
    boolean flag = false;
    if (obj != null) {
      flag = true;
    }
    return flag;
  }

  /**
   * 判断一个字符串对象是否不是""或null
   *
   * @param str 要判断的字符串对象
   * @return
   */
  public static boolean isNotEmpty(String str) {
    return StringUtils.isNotEmpty(str);
  }

  public static boolean isBlank(String str) {
    return StringUtils.isBlank(str);
  }

  /**
   * 将一个字符串的前后空白去掉，如果为null转换成""
   *
   * @param str 要操作的字符串对象
   * @return
   */
  public static String trimToEmpty(String str) {
    return StringUtils.trimToEmpty(str);
  }

  /**
   * 将一个字符串的前后空白去掉，如果为""转换成null
   *
   * @param str
   * @return
   */
  public static String trimToNull(String str) {
    return StringUtils.trimToNull(str);
  }

  /**
   * 用指定的分割字符连接数组元素
   *
   * @param array     对象数组
   * @param separator 分割字符
   * @return
   */
  public static String join(Object[] array, String separator) {
    return StringUtils.join(array, separator);
  }

  /**
   * 用指定的分割字符连接数组元素
   *
   * @param iterable  对象数组
   * @param separator 分割字符
   * @return
   */
  public static String join(Iterable<?> iterable, String separator) {
    return StringUtils.join(iterable, separator);
  }

  /**
   * 获取文件路径中文件扩展名，不含.
   *
   * @param filePath 文件路径
   * @return
   */
  public static String getFileExtName(String filePath) {
    filePath = filePath.replace('\\', '/');
    int pos = filePath.lastIndexOf('/');
    if (pos > 0) {
      filePath = filePath.substring(pos + 1, filePath.length());
    }
    pos = filePath.lastIndexOf('.');
    String baseName = "";

    if (pos > 0) {
      baseName = filePath.substring(pos + 1, filePath.length());
    }
    return baseName;
  }

  public static String substringBeforeLast(String str, String separator) {
    return StringUtils.substringBeforeLast(str, separator);
  }


  /**
   * 字符串转成Long
   *
   * @param num ：要转化的数字字符串
   * @param def ：默认值
   * @return 返回 Long
   */
  public static Long getLong(String num, long def) {
    if (isEmpty(num)) {
      return def;
    }
    long ret = def;
    int i = num.indexOf(".");
    if (i == 0) {
      num = "0";
    } else if (i > 0) {
      num = num.substring(0, i);
    }
    try {
      ret = Long.parseLong(num);
    } catch (NumberFormatException ex) {
      ex.printStackTrace();
    }
    return ret;
  }

  /**
   * 字符串转成Long
   *
   * @param num ：要转化的数字字符串
   * @return 返回 Long
   */
  public static Long getLong(String num) {
    return getLong(num, 0);
  }

  public static Long getLong(Object num) {
    return getLong(getString(num));
  }

  public static Long getLong(Object num, long def) {
    return getLong(getString(num), def);
  }

  /**
   * 字符串转成Integer
   *
   * @param num ：要转化的数字字符串
   * @param def ：默认值
   * @return 返回 Integer
   */
  public static Integer getInteger(String num, int def) {
    if (isEmpty(num)) {
      return def;
    }
    int ret = def;
    try {
      ret = Integer.valueOf(num);
    } catch (NumberFormatException ex) {
      ex.printStackTrace();
    }
    return ret;
  }

  /**
   * 字符串转成Integer
   *
   * @param num ：要转化的数字字符串
   * @return 返回 Integer
   */
  public static Integer getInteger(String num) {
    if (isEmpty(num)) {
      return null;
    }
    int ret = 0;
    int i = num.indexOf(".");
    if (i == 0) {
      num = "0";
    } else if (i > 1) {
      num = num.substring(0, i);
    }
    try {
      ret = Integer.valueOf(num);
    } catch (NumberFormatException ex) {
      ex.printStackTrace();
    }
    return ret;
  }

  public static Integer getInteger(Object num) {
    return getInteger(getString(num));
  }

  public static Integer getInteger(Object num, int def) {
    return getInteger(getString(num), def);
  }

  /**
   * 替换字符
   *
   * @param str
   * @param searchChar
   * @param replaceChar
   * @return
   */
  public static String replaceChars(String str, char searchChar, char replaceChar) {
    return StringUtils.replaceChars(str, searchChar, replaceChar);
  }

  /**
   * 替换字符串
   *
   * @param str
   * @param searchString
   * @param replaceString
   * @return
   */
  public static String replace(String str, String searchString, String replaceString) {
    return StringUtils.replace(str, searchString, replaceString);
  }

  /**
   * if the input string is empty, then return the default string
   *
   * @param obj
   * @param def
   * @return string
   */
  public static String getString(Object obj, String def) {
    if (obj == null) {
      return def;
    }
    String result = obj.toString();
    return result.length() == 0 ? def : result;
  }

  public static String getString(Object obj) {
    return getString(obj, "");
  }

  public static String replaceFileSep(String sep) {
    if (File.separator.equals("\\")) {
      return StringTools.replace(sep, "/", "\\");
    } else {
      return StringTools.replace(sep, "\\", "/");
    }
  }

  public static String replaceUrlSep(String url) {
    return StringTools.replace(url, "\\", "/");
  }

  public static String escapeHtml(String text) {
    String temp = StringTools.replace(text, "&", "&amp;");

    temp = StringTools.replace(temp, " ", "&nbsp;");
    temp = StringTools.replace(temp, ">", "&gt;");
    temp = StringTools.replace(temp, "<", "&lt;");
    temp = StringTools.replace(temp, "\"", "&quot;");
    temp = StringTools.replace(temp, "\n", "<br>");
    temp = StringTools.replace(temp, "\t", "&nbsp;&nbsp;&nbsp;&nbsp;");

    return temp;
  }

  public static String stripUnsafeTag(String text) {
    String temp = text.replaceAll("<script[^>]*>([^<]*)</script>", "");
    return temp;
  }

  public static boolean checkYearMonth(String validYear) {
    Pattern p = Pattern.compile("^\\d{4}((0\\d)|(1[0-2])|([0-9]))$");
    Matcher m = p.matcher(validYear);
    return m.matches();
  }

  public static String formatMillsToString(Long mills) {
    if (StringTools.isEmpty(mills)) {
      return "00:00:00";
    }
    long ss = (mills / 1000) % 60;
    long mm = (mills / 60000) % 60;
    long hh = mills / 3600000;
    return getFormatString(hh) + ":" + getFormatString(mm) + ":" + getFormatString(ss);
  }

  public static String formatMillsToString2(Long mills) {
    if (StringTools.isEmpty(mills)) {
      return "00:00";
    }
    long ss = (mills / 1000) % 60;
    long mm = mills / 60000;
    return getFormatString(mm) + ":" + getFormatString(ss);
  }

  public static String getFormatString(long time) {
    if (time < 10l) {
      return "0" + time;
    }
    return time + "";
  }

  public static String clearEmptyLine(String in) {
    Pattern pattern = Pattern.compile("\n");
    Matcher matcher = pattern.matcher(in);
    if (matcher.matches()) {
      return matcher.replaceAll("\n");
    }
    return in;
  }

  public static String integerToString(Integer obj) {
    if (obj == null) {
      return null;
    }
    if (obj < 10) {
      return "0" + obj;
    }
    return obj + "";
  }

  /**
   * 位数不足，前面补0
   *
   * @param code
   * @param len
   * @return
   */
  public static String codeAddOne(String code, int len) {
    Integer intOrder = Integer.parseInt(code);
    String strNo = intOrder.toString();
    while (strNo.length() < len) {
      strNo = "0" + strNo;
    }
    return strNo;
  }

  /**
   * 16进制转十进制
   *
   * @param hex ：
   * @return ：
   */
  public static Integer hexToDec(String hex) {
    for (int i = 0; i < hex.length(); i++) {
      if (!((hex.charAt(i) >= 48 && hex.charAt(i) <= 57) || (hex.charAt(i) >= 'a' && hex.charAt(i) <= 'f') || (hex.charAt(i) >= 'A' && hex.charAt(i) <= 'F'))) {
        return 0;
      }
    }
    return Integer.valueOf(hex, 16);
  }

  /**
   * 十进制转16进制
   *
   * @param num ：
   * @return ：
   */
  public static String decToHex(Integer num) {
    if (num == null) {
      return "0";
    }
    return Integer.toHexString(num);
  }

  /**
   * 判断字符是否为
   *
   * @param text
   * @return
   */
  public static boolean isEmptyOrNullString(String text) {
    if (isEmpty(text)) return true;

    if ("null".equals(text) || "(null)".equals(text)) return true;

    return false;
  }

  public static String[] convert2Array(String text, String split) {
    if (StringTools.isEmpty(text)) {
      return null;
    }
    String[] strArray = null;
    if (text.indexOf(split) > -1) {
      strArray = text.split(split);
    } else {
      strArray = new String[]{text};
    }
    return strArray;
  }

  public static String[] convert2Array(String text) {
    return convert2Array(text, ",");
  }

  public static Integer[] convert2IntegerArray(String text, String split) throws NumberFormatException {
    String[] strArr = convert2Array(text, split);
    if (strArr == null) {
      return null;
    }
    Integer[] intArr = new Integer[strArr.length];
    for (int i = 0; i < strArr.length; i++) {
      intArr[i] = Integer.valueOf(strArr[i]);
    }
    return intArr;

  }

  public static Integer[] convert2IntegerArray(String text) throws NumberFormatException {
    return convert2IntegerArray(text, ",");
  }

  public static List<String> convert2StringList(String text, String split) throws NumberFormatException {
    List<String> strList = new ArrayList<String>();
    String[] strArr = convert2Array(text, split);
    for (String s : strArr) {
      strList.add(s);
    }
    return strList;
  }

  public static List<String> convert2StringList(String text) {
    return convert2StringList(text, ",");
  }

  public static List<Long> convert2LongList(String text, String split) throws NumberFormatException {
    List<Long> lList = new ArrayList<Long>();
    String[] strArr = convert2Array(text, split);
    if (StringTools.isEmpty(strArr)) {
      return null;
    }
    for (String s : strArr) {
      Long temp = Long.valueOf(s);
      lList.add(temp);
    }
    return lList;
  }

  public static List<Long> convert2LongList(String text) throws NumberFormatException {
    return convert2LongList(text, ",");
  }

  public static List<Integer> convert2IntegerList(String text, String split) throws NumberFormatException {
    List<Integer> iList = new ArrayList<Integer>();
    String[] strArr = convert2Array(text, split);
    if (StringTools.isEmpty(strArr)) {
      return null;
    }
    for (String s : strArr) {
      Integer temp = Integer.valueOf(s);
      iList.add(temp);
    }
    return iList;
  }

  public static List<Integer> convert2IntegerList(String text) throws NumberFormatException {
    return convert2IntegerList(text, ",");
  }

  public static String concat(String symbol, String... param) {
    if (param == null) {
      return null;
    }
    String result = "";
    String[] params = param;
    for (int i = 0; i < params.length; i++) {
      result = i == 0 ? params[i] : result + symbol + params[i];
    }
    return result;
  }

  public static String[] split(final String str, final String separatorChars) {
    return StringUtils.split(str, separatorChars);
  }

  public static Map<String, Object> split2map(final String paramStr) {
    return split2map(",", ":", paramStr);
  }

  /**
   * 将字符串根据两个分隔符分割为Map
   *
   * @author lh
   * @date 2015年10月26日
   */
  public static Map<String, Object> split2map(final String separatorChar, final String separatorChar2, final String paramStr) {
    if (StringTools.isBlank(paramStr)) return null;

    String[] splitList = StringUtils.split(paramStr, ",");
    if (CollectionTools.isEmpty(splitList)) return null;

    Map<String, Object> rsMap = new HashMap<String, Object>(splitList.length, 1);

    for (String str : splitList) {
      String[] p = StringUtils.split(str, ":", 2);
      if (CollectionTools.isEmpty(p) || p.length < 2) continue;

      rsMap.put(p[0].trim(), p[1].trim());
    }

    return rsMap;
  }

  public static boolean isNotBlank(String str) {
    return StringUtils.isNotBlank(str);
  }

  public static String lowerCase(String str) {
    if (str == null) {
      return null;
    }
    return str.toLowerCase();
  }

  /**
   * 比较两个字符串，如果其中一个字符串为blank，计算不相等
   *
   * @param arg1
   * @param arg2
   * @return
   * @author gtli
   */
  public static boolean equalsString(String arg1, String arg2) {
    if (isBlank(arg1) || isBlank(arg2)) {
      return false;
    }
    return arg1.equals(arg2);
  }

  /**
   * 驼峰转下划线
   *
   * @param str
   * @return
   * @author sunninghai
   * @date 2015年11月5日
   */
  public static String camelToUnderScore(String str) {
    return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, str);
  }


  /**
   *
   */
  public static String getHost(String url) {
    if (url.indexOf("://") > 0) {
      url = url.substring(url.indexOf("://") + 3, url.length());
    }
    if (url.indexOf("/") > 0) {
      url = url.substring(0, url.indexOf("/"));
    }
    if (url.indexOf(":") > 0) {
      url = url.substring(0, url.indexOf(":"));
    }
    return url;
  }

  public static String getShotName(String url) {
    if (!url.contains(".")) {
      return null;
    }
    if (url.lastIndexOf(".") > 0) {
      url = url.substring(0, url.lastIndexOf("."));
    }
    if (url.lastIndexOf(".") > 0) {
      url = url.substring(0, url.lastIndexOf("."));
    }
    if (url.indexOf(".") > 0) {
      url = url.substring(url.indexOf(".") + 1, url.length());
    }
    return url;
  }

  public static String getShortName(String url) {
    String shortName = null;
    int index = url.indexOf(".");
    if (!url.contains(".") || index == 0) {
      return null;
    }
    if (index > 0) {
      shortName = url.substring(0, index);
    }
    return shortName;
  }

  public static String getFirstDomain(String url) {
    Pattern p = Pattern.compile("(?<=http://|\\.)[^.]*?\\.(com|cn|net|org|biz|info|cc|tv)", Pattern.CASE_INSENSITIVE);
    Matcher matcher = p.matcher(url);
    matcher.find();
    return matcher.group();
  }

  public static boolean isEmail(String email) {

    Pattern regex = Pattern.compile("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)*$");
    Matcher matcher = regex.matcher(email);
    boolean isMatched = matcher.matches();
    return isMatched;
  }

  public static boolean isMobile(String mobiles) {
    Pattern p = Pattern.compile("^[1]([3]|[5]|[4]|[8]|[7]|[6]|[9])[0-9]{9}$");
    Matcher m = p.matcher(mobiles);
    return m.matches();
  }


  public static Integer long2Integer(Long l) {
    if (l == null) {
      return null;
    }
    return Integer.parseInt((new Long(l.toString())).toString());

  }

  public static Long string2Long(Object s) {
    if (s == null || s.equals("")) {
      return null;
    }
    return new Long(s.toString());

  }

  public static Long object2Long(Object s) {
    if (s == null || s.equals("")) {
      return null;
    }
    return new Long(s.toString());

  }

  public static Integer object2Integer(Object s) {
    if (s == null || s.equals("")) {
      return null;
    }
    return new Integer(s.toString());

  }

  public static String object2String(Object s) {
    if (s == null || s.equals("")) {
      return null;
    }
    return new String(s.toString());

  }

  public static String escapeQuotes(String oldString) {
    if (StringTools.isNotBlank(oldString)) {
      oldString = oldString.replaceAll("&quot;", "\"").replaceAll("\"", "\\\"");
    }
    return oldString;
  }

  public static String replaceHtml(String string) {
    if (isNotEmpty(string)) {
      string = string.replaceAll("'", "&acute;");
      string = string.replaceAll("\"", "&quot;");
    }
    return string;
  }

  public static String concatUrl(String prefixbucket, String relativeUrl) {
    if (isEmpty(prefixbucket) || isEmpty(relativeUrl)) {
      return prefixbucket;
    } else if (relativeUrl.startsWith("https:") || relativeUrl.startsWith("//")) {
      //存在http://
      return relativeUrl;
    } else if (!prefixbucket.endsWith("/") && !relativeUrl.startsWith("/")) {
      //中间没有/分割自动添加
      return prefixbucket.concat("/").concat(relativeUrl);
    } else if (prefixbucket.endsWith("/") && relativeUrl.startsWith("/")) {
      //两头都有/去掉一个
      prefixbucket = substringBeforeLast(prefixbucket, "/");
      return prefixbucket.concat(relativeUrl);
    } else {
      return prefixbucket.concat(relativeUrl);
    }
  }

  public static String convertNum(Integer num) {
    String[] numsAry = {"0", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十"};
    if (num > numsAry.length) {
      return "";
    }
    return numsAry[num];
  }

  public static String convertWeekNum(Integer num) {
    String[] numsAry = {"0", "一", "二", "三", "四", "五", "六", "日"};
    if (num > numsAry.length) {
      return "";
    }
    return numsAry[num];
  }

  /**
   * 验证 yyyyMMdd类型的字符串时间
   */
  public static boolean isDate(String date) {
    Pattern p = Pattern.compile("^\\d{8}$");
    Matcher m = p.matcher(date);
    return m.matches();
  }

  /**
   * 验证 yyyyMM类型的字符串时间
   */
  public static boolean isYYYYMMDate(String date) {
    Pattern p = Pattern.compile("^\\d{6}$");
    Matcher m = p.matcher(date);
    return m.matches();
  }

  /**
   * 判断字符串是整数或者保留两位小数
   *
   * @param str
   * @return
   */
  public static boolean isIntegerOrTwoDecimal(String str) {
    Pattern pattern = Pattern.compile("^[+]?([0-9]+(.[0-9]{2})?)$");
    return pattern.matcher(str).matches();
  }

  /**
   * 简单验证身份证格式
   * 15位数字/14位数字,1为字母／18位数字／17位数字，最后一位Xx
   *
   * @param cardId
   * @return
   */
  public static boolean isCardId(String cardId) {
    Pattern pattern = Pattern.compile("(\\d{14}[0-9a-zA-Z])|(\\d{17}[0-9a-zA-Z])");
    return pattern.matcher(cardId).matches();
  }

  public static List<Long> spliteStr2LongList(String string, String separator) {
    List<Long> longList = null;
    if (string != null && !"".equals(separator)) {
      longList = Lists.newArrayList();
      List<String> strings = Splitter.on(separator).trimResults().omitEmptyStrings().splitToList(string);
      try {
        for (String s : strings) {
          longList.add(Long.valueOf(s));
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    return longList;
  }


  /**
   * Returns the specified array as a comma-delimited (',') string.
   *
   * @param array the array whose contents will be converted to a string.
   * @return the array's contents as a comma-delimited (',') string.
   * @since 1.0
   */
  public static String toString(Object[] array) {
    return toDelimitedString(array, ",");
  }


  /**
   * Returns the array's contents as a string, with each element delimited by the specified
   * {@code delimiter} argument.  Useful for {@code toString()} implementations and log messages.
   *
   * @param array     the array whose contents will be converted to a string
   * @param delimiter the delimiter to use between each element
   * @return a single string, delimited by the specified {@code delimiter}.
   * @since 1.0
   */
  public static String toDelimitedString(Object[] array, String delimiter) {
    if (array == null || array.length == 0) {
      return "";
    }
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < array.length; i++) {
      if (i > 0) {
        sb.append(delimiter);
      }
      sb.append(array[i]);
    }
    return sb.toString();
  }

  public static String formatWeekIntStrToWeekStr(String weekIntStr) {
    StringBuilder sb = new StringBuilder();
    List<Long> longList = spliteStr2LongList(weekIntStr, COMMA_SEPARATOR);
    if (CollectionTools.isNotEmpty(longList)) {
      Collections.sort(longList);
      for (Long num : longList) {
        if ("".equals(sb.toString())) {
          sb.append("周" + convertWeekNum(num.intValue()));
        } else {
          sb.append("、" + convertWeekNum(num.intValue()));
        }
      }

    }
    return sb.toString();
  }


  public static String toDelimitedString(Collection c, String delimiter) {
    if (c == null || c.isEmpty()) {
      return EMPTY;
    }
    return join(c.iterator(), delimiter);
  }

  public static String join(Iterator<?> iterator, String separator) {
    final String empty = "";

    // handle null, zero and one elements before building a buffer
    if (iterator == null) {
      return null;
    }
    if (!iterator.hasNext()) {
      return empty;
    }
    Object first = iterator.next();
    if (!iterator.hasNext()) {
      return first == null ? empty : first.toString();
    }

    // two or more elements
    StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
    if (first != null) {
      buf.append(first);
    }

    while (iterator.hasNext()) {
      if (separator != null) {
        buf.append(separator);
      }
      Object obj = iterator.next();
      if (obj != null) {
        buf.append(obj);
      }
    }
    return buf.toString();
  }

  public static Set<String> splitToSet(String delimited, String separator) {
    if (delimited == null || separator == null) {
      return null;
    }
    String[] split = split(delimited, separator.charAt(0));
    return asSet(split);
  }

  public static String[] split(String line) {
    return split(line, DEFAULT_DELIMITER_CHAR);
  }

  public static String[] split(String line, char delimiter) {
    return split(line, delimiter, DEFAULT_QUOTE_CHAR);
  }

  public static String[] split(String line, char delimiter, char quoteChar) {
    return split(line, delimiter, quoteChar, quoteChar);
  }

  public static String[] split(String line, char delimiter, char beginQuoteChar, char endQuoteChar) {
    return split(line, delimiter, beginQuoteChar, endQuoteChar, false, true);
  }


  /**
   * Splits the specified delimited String into tokens, supporting quoted tokens so that quoted strings themselves
   * won't be tokenized.
   * <p/>
   * This method's implementation is very loosely based (with significant modifications) on
   * <a href="http://blogs.bytecode.com.au/glen">Glen Smith</a>'s open-source
   * <a href="http://opencsv.svn.sourceforge.net/viewvc/opencsv/trunk/src/au/com/bytecode/opencsv/CSVReader.java?&view=markup">CSVReader.java</a>
   * file.
   * <p/>
   * That file is Apache 2.0 licensed as well, making Glen's code a great starting point for us to modify to
   * our needs.
   *
   * @param aLine          the String to parse
   * @param delimiter      the delimiter by which the <tt>line</tt> argument is to be split
   * @param beginQuoteChar the character signifying the start of quoted text (so the quoted text will not be split)
   * @param endQuoteChar   the character signifying the end of quoted text
   * @param retainQuotes   if the quotes themselves should be retained when constructing the corresponding token
   * @param trimTokens     if leading and trailing whitespace should be trimmed from discovered tokens.
   * @return the tokens discovered from parsing the given delimited <tt>line</tt>.
   */
  public static String[] split(String aLine, char delimiter, char beginQuoteChar, char endQuoteChar,
                               boolean retainQuotes, boolean trimTokens) {
    String line = clean(aLine);
    if (line == null) {
      return null;
    }

    List<String> tokens = new ArrayList<String>();
    StringBuilder sb = new StringBuilder();
    boolean inQuotes = false;

    for (int i = 0; i < line.length(); i++) {

      char c = line.charAt(i);
      if (c == beginQuoteChar) {
        // this gets complex... the quote may end a quoted block, or escape another quote.
        // do a 1-char lookahead:
        if (inQuotes  // we are in quotes, therefore there can be escaped quotes in here.
                && line.length() > (i + 1)  // there is indeed another character to check.
                && line.charAt(i + 1) == beginQuoteChar) { // ..and that char. is a quote also.
          // we have two quote chars in a row == one quote char, so consume them both and
          // put one on the token. we do *not* exit the quoted text.
          sb.append(line.charAt(i + 1));
          i++;
        } else {
          inQuotes = !inQuotes;
          if (retainQuotes) {
            sb.append(c);
          }
        }
      } else if (c == endQuoteChar) {
        inQuotes = !inQuotes;
        if (retainQuotes) {
          sb.append(c);
        }
      } else if (c == delimiter && !inQuotes) {
        String s = sb.toString();
        if (trimTokens) {
          s = s.trim();
        }
        tokens.add(s);
        sb = new StringBuilder(); // start work on next token
      } else {
        sb.append(c);
      }
    }
    String s = sb.toString();
    if (trimTokens) {
      s = s.trim();
    }
    tokens.add(s);
    return tokens.toArray(new String[tokens.size()]);
  }


  private static <E> Set<E> asSet(E... elements) {
    if (elements == null || elements.length == 0) {
      return Collections.emptySet();
    }

    if (elements.length == 1) {
      return Collections.singleton(elements[0]);
    }

    LinkedHashSet<E> set = new LinkedHashSet<E>(elements.length * 4 / 3 + 1);
    Collections.addAll(set, elements);
    return set;
  }

  /**
   * Returns a 'cleaned' representation of the specified argument.  'Cleaned' is defined as the following:
   * <p/>
   * <ol>
   * <li>If the specified <code>String</code> is <code>null</code>, return <code>null</code></li>
   * <li>If not <code>null</code>, {@link String#trim() trim()} it.</li>
   * <li>If the trimmed string is equal to the empty String (i.e. &quot;&quot;), return <code>null</code></li>
   * <li>If the trimmed string is not the empty string, return the trimmed version</li>.
   * </ol>
   * <p/>
   * Therefore this method always ensures that any given string has trimmed text, and if it doesn't, <code>null</code>
   * is returned.
   *
   * @param in the input String to clean.
   * @return a populated-but-trimmed String or <code>null</code> otherwise
   */
  public static String clean(String in) {
    String out = in;

    if (in != null) {
      out = in.trim();
      if (out.equals(EMPTY)) {
        out = null;
      }
    }

    return out;
  }


  public static boolean hasText(String str) {
    if (!hasLength(str)) {
      return false;
    }
    int strLen = str.length();
    for (int i = 0; i < strLen; i++) {
      if (!Character.isWhitespace(str.charAt(i))) {
        return true;
      }
    }
    return false;
  }


  public static boolean hasLength(String str) {
    return (str != null && str.length() > 0);
  }

  public static String formatTeacherStr(String teacherStr) {
    StringBuilder sb = new StringBuilder();
    List<String> strings = Splitter.on(COMMA_SEPARATOR).trimResults().omitEmptyStrings().splitToList(teacherStr);
    if (CollectionTools.isNotEmpty(strings)) {
      for (String string : strings) {
        if (!"".equals(string)) {
          sb.append(string + "、");
        }
      }
    }
    String teachers = sb.toString();
    if (isNotEmpty(teachers)) {
      return teachers.substring(0, teachers.length() - 1);
    }
    return teachers;
  }


  /**
   * 忽略大小写的相等判断
   *
   * @param src
   * @param des
   * @return
   */
  public static boolean equalsIgnoreCase(String src, String des) {
    if (src == null && des == null) {
      return true;
    } else if (src == null) {
      return false;
    } else if (des == null) {
      return false;
    } else if (src.toLowerCase().equals(des.toLowerCase())) {
      return true;
    } else {
      return false;
    }
  }


  /**
   * 忽略大小写的是否以特定字符开头
   *
   * @param src
   * @param des
   * @return
   */
  public static boolean startsWithIgnoreCase(String src, String des) {
    if (src == null && des == null) {
      return true;
    } else if (src == null) {
      return false;
    } else if (des == null) {
      return false;
    } else if (src.toLowerCase().indexOf(des.toLowerCase()) == 0) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * 是否以特定字符开头
   *
   * @param src
   * @param des
   * @return
   */
  public static boolean startsWith(String src, String des) {
    if (src == null && des == null) {
      return true;
    } else if (src == null) {
      return false;
    } else if (des == null) {
      return false;
    } else if (src.toLowerCase().indexOf(des) == 0) {
      return true;
    } else {
      return false;
    }
  }


  public static String replaceEach(String text, String[] searchList, String[] replacementList) {
    return replaceEach(text, searchList, replacementList, false, 0);
  }

  public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) {
    int timeToLive = searchList == null ? 0 : searchList.length;
    return replaceEach(text, searchList, replacementList, true, timeToLive);
  }

  private static String replaceEach(String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) {
    if (text != null && isNotEmpty(text) && searchList != null && searchList.length != 0 && replacementList != null && replacementList.length != 0) {
      if (timeToLive < 0) {
        throw new IllegalStateException("Aborting to protect against StackOverflowError - output of one loop is the input of another");
      } else {
        int searchLength = searchList.length;
        int replacementLength = replacementList.length;
        if (searchLength != replacementLength) {
          throw new IllegalArgumentException("Search and Replace array lengths don't match: " + searchLength + " vs " + replacementLength);
        } else {
          boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
          int textIndex = -1;
          int replaceIndex = -1;
          int tempIndex = -1;

          int start;
          for (start = 0; start < searchLength; ++start) {
            if (!noMoreMatchesForReplIndex[start] && searchList[start] != null && isNotEmpty(searchList[start]) && replacementList[start] != null) {
              tempIndex = text.indexOf(searchList[start]);
              if (tempIndex == -1) {
                noMoreMatchesForReplIndex[start] = true;
              } else if (textIndex == -1 || tempIndex < textIndex) {
                textIndex = tempIndex;
                replaceIndex = start;
              }
            }
          }

          if (textIndex == -1) {
            return text;
          } else {
            start = 0;
            int increase = 0;

            int i;
            for (i = 0; i < searchList.length; ++i) {
              if (searchList[i] != null && replacementList[i] != null) {
                i = replacementList[i].length() - searchList[i].length();
                if (i > 0) {
                  increase += 3 * i;
                }
              }
            }

            increase = Math.min(increase, text.length() / 5);
            StringBuilder buf = new StringBuilder(text.length() + increase);

            while (textIndex != -1) {
              for (i = start; i < textIndex; ++i) {
                buf.append(text.charAt(i));
              }

              buf.append(replacementList[replaceIndex]);
              start = textIndex + searchList[replaceIndex].length();
              textIndex = -1;
              replaceIndex = -1;
              tempIndex = -1;

              for (i = 0; i < searchLength; ++i) {
                if (!noMoreMatchesForReplIndex[i] && searchList[i] != null && isNotEmpty(searchList[i]) && replacementList[i] != null) {
                  tempIndex = text.indexOf(searchList[i], start);
                  if (tempIndex == -1) {
                    noMoreMatchesForReplIndex[i] = true;
                  } else if (textIndex == -1 || tempIndex < textIndex) {
                    textIndex = tempIndex;
                    replaceIndex = i;
                  }
                }
              }
            }

            i = text.length();

            for (i = start; i < i; ++i) {
              buf.append(text.charAt(i));
            }

            String result = buf.toString();
            if (!repeat) {
              return result;
            } else {
              return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
            }
          }
        }
      }
    } else {
      return text;
    }
  }


  public static String capitalize(String str) {
    int strLen;
    if (str != null && (strLen = str.length()) != 0) {
      char firstChar = str.charAt(0);
      return Character.isTitleCase(firstChar) ? str : (new StringBuilder(strLen)).append(Character.toTitleCase(firstChar)).append(str.substring(1)).toString();
    } else {
      return str;
    }
  }

  public static String uncapitalize(String str) {
    int strLen;
    if (str != null && (strLen = str.length()) != 0) {
      char firstChar = str.charAt(0);
      return Character.isLowerCase(firstChar) ? str : (new StringBuilder(strLen)).append(Character.toLowerCase(firstChar)).append(str.substring(1)).toString();
    } else {
      return str;
    }
  }

  public static String substringAfterLast(String str, String separator) {
    if (isEmpty(str)) {
      return str;
    } else if (isEmpty(separator)) {
      return "";
    } else {
      int pos = str.lastIndexOf(separator);
      return pos != -1 && pos != str.length() - separator.length() ? str.substring(pos + separator.length()) : "";
    }
  }


  public static String substringBetween(String str, String tag) {
    return substringBetween(str, tag, tag);
  }

  public static String substringBetween(String str, String open, String close) {
    if (str != null && open != null && close != null) {
      int start = str.indexOf(open);
      if (start != -1) {
        int end = str.indexOf(close, start + open.length());
        if (end != -1) {
          return str.substring(start + open.length(), end);
        }
      }

      return null;
    } else {
      return null;
    }
  }


  /**
   * 驼峰命名法工具
   *
   * @return toCamelCase(" hello_world ") == "helloWorld"
   * toCapitalizeCamelCase("hello_world") == "HelloWorld"
   * toUnderScoreCase("helloWorld") = "hello_world"
   */
  public static String toCamelCase(String s) {
    if (s == null) {
      return null;
    }

    s = s.toLowerCase();

    StringBuilder sb = new StringBuilder(s.length());
    boolean upperCase = false;
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);

      if (c == SEPARATOR) {
        upperCase = true;
      } else if (upperCase) {
        sb.append(Character.toUpperCase(c));
        upperCase = false;
      } else {
        sb.append(c);
      }
    }

    return sb.toString();
  }


  /**
   * 驼峰命名法工具
   *
   * @return toCamelCase(" hello_world ") == "helloWorld"
   * toCapitalizeCamelCase("hello_world") == "HelloWorld"
   * toUnderScoreCase("helloWorld") = "hello_world"
   */
  public static String toUnderScoreCase(String s) {
    if (s == null) {
      return null;
    }

    StringBuilder sb = new StringBuilder();
    boolean upperCase = false;
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);

      boolean nextUpperCase = true;

      if (i < (s.length() - 1)) {
        nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
      }

      if ((i > 0) && Character.isUpperCase(c)) {
        if (!upperCase || !nextUpperCase) {
          sb.append(SEPARATOR);
        }
        upperCase = true;
      } else {
        upperCase = false;
      }

      sb.append(Character.toLowerCase(c));
    }

    return sb.toString();
  }


//  public static void main(String[] args) {
//    String encoding = "UTF-8";
//    File file = new File("/Users/gxb/Documents/city-code.json");
//    Long filelength = file.length();
//    int id = 0;
//    byte[] filecontent = new byte[filelength.intValue()];
//    try {
//      FileInputStream in = new FileInputStream(file);
//      in.read(filecontent);
//      in.close();
//      String content = new String(filecontent, encoding);
//      JSONArray josn = JSONObject.parseArray(content);
//
//      JSONArray newJson = new JSONArray();
//
//      for (int i = 0; i < josn.size(); i++) {
//        id++;
//        JSONObject o = (JSONObject) josn.get(i);
//        String code = o.getString("code");
//        String name = o.getString("name");
//
//        JSONObject object = new JSONObject();
//        object.put("label", name);
//        object.put("value", id);
//        object.put("code", code);
//        JSONArray scitys = new JSONArray();
//        System.out.println("INSERT INTO zygj_zone_city (id, name, code, parent_id) VALUES (" + id + ", '" + name + "', '" + code + "', 0);");
//        if ("北京".equals(name) || "上海".equals(name) || "天津".equals(name) || "重庆".equals(name) || "澳门".equals(name) || "香港".equals(name)) {
//
//        } else {
//          JSONArray cities = o.getJSONArray("cities");
//          int parentId = id;
//          for (int j = 0; j < cities.size(); j++) {
//            id++;
//            JSONObject newcity = new JSONObject();
//            JSONObject city = (JSONObject) cities.get(j);
//            String code1 = city.getString("code");
//            String name1 = city.getString("name");
//            newcity.put("label", name1);
//            newcity.put("value", id);
//            newcity.put("code", code1);
//            System.out.println("INSERT INTO zygj_zone_city (id, name, code, parent_id) VALUES (" + id + ", '" + name1 + "', '" + code1 + "', " + parentId + ");");
//            scitys.add(newcity);
//          }
//        }
//        object.put("children", scitys);
//        newJson.add(object);
//      }
//      String t = JSONArray.toJSONString(newJson);
//      System.out.println(t);
//    } catch (FileNotFoundException e) {
//      e.printStackTrace();
//    } catch (IOException e) {
//      e.printStackTrace();
//    }
//
//
//  }


}
