package com.docus.server.collect.web.utils;


import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.constraints.NotNull;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class XaUtils {

    private static final String UNIT = "万千佰拾亿千佰拾万千佰拾元角分";
    private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖";
    private static final double MAX_VALUE = 9999999999999.99D;


    /**
     * 判断对象是否Empty(null或元素为0)<br>
     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
     *
     * @param pObj 待检查对象
     * @return boolean 返回的布尔值
     */
    @SuppressWarnings("rawtypes")
    public static boolean isEmpty(Object pObj) {
        if (pObj == null) {
            return true;
        }
        if (pObj == "") {
            return true;
        }
        if (pObj instanceof String) {
            if (((String) pObj).trim().length() == 0) {
                return true;
            }
        } else if (pObj instanceof Collection) {
            if (((Collection) pObj).size() == 0) {
                return true;
            }
        } else if (pObj instanceof Map) {
            if (((Map) pObj).size() == 0) {
                return true;
            }
        } else if (isArray(pObj)) {
            if (Array.getLength(pObj) == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断对象是否为NotEmpty(!null或元素>0)<br>
     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
     *
     * @param pObj 待检查对象
     * @return boolean 返回的布尔值
     */
    @SuppressWarnings("rawtypes")
    public static boolean isNotEmpty(Object pObj) {
        if (pObj == null) {
            return false;
        }
        if (pObj == "") {
            return false;
        }
        if (pObj instanceof String) {
            if (((String) pObj).trim().length() == 0) {
                return false;
            }
        } else if (pObj instanceof Collection) {
            if (((Collection) pObj).size() == 0) {
                return false;
            }
        } else if (pObj instanceof Map) {
            if (((Map) pObj).size() == 0) {
                return false;
            }
        } else if (isArray(pObj)) {
            if (Array.getLength(pObj) == 0) {
                return false;
            }
        }
        return true;
    }

    public static boolean isArray(Object pObj) {
        if (pObj == null) {
            return false;
        }
        if (pObj.getClass().isArray()) {
            return true;
        }
        return false;
    }


    /**
     * 【tomcat】获取访问者真实IP
     * http://www.cnblogs.com/puyangsky/p/5555859.html
     */
    @Deprecated
    public static String getClientIpAddress(@NotNull HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 获取访问者真实IP
     * 经过nginx 代理也可以正常获取ip
     * <p>
     * request.getLocalAddr(),往往有问题
     *
     * @param request
     * @return
     */
    public static String getClientIpAddress2(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            //多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = ip.indexOf(",");
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            return ip;
        }
        return request.getRemoteAddr();
    }





    public static String getCmsLoginedUserId(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String userId = session.getAttribute("loginUserId") + "";
        if (isNotEmpty(userId)) {
            return userId;
        }
        return "";
    }

    /**
     * 往文件写数据
     */
    public static void WriteFile(String content, String filePath, String fileName) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        File f1 = new File(filePath + File.separator + fileName);
        FileUtils.writeStringToFile(f1, content, "utf-8");
    }

    public static List<Long> getIds(String[] arr) {
        if (isEmpty(arr) || arr.length == 0) {
            return new ArrayList<>();
        }
        List<Long> idsList = new ArrayList<>();
        for (String str : arr) {
            if (isNotEmpty(str)) {
                idsList.add(Long.valueOf(str));
            }
        }
        return idsList;
    }

    /**
     * Boolean 使用前要进行判断,否则空指针异常
     * 可以参加 {@link org.apache.commons.lang3.BooleanUtils}
     * 页面返回1,2,3
     *
     * @param bool
     * @return
     */
    public static Boolean getBool(String bool) {
        return Boolean.parseBoolean(bool);
    }

    public static String getNutNullStr(Object o, String defaultValue) {
        if (isEmpty(o) || "undefined".equalsIgnoreCase(String.valueOf(o))) {
            return defaultValue;
        }
        return o.toString();
    }

    public static Long getNutNullLong(Object o, Long defaultValue) {
        if (isEmpty(o)) {
            return defaultValue;
        }
        return NumberUtils.toLong(o.toString(), defaultValue);
    }

    public static double getNutNullDouble(Object o, double defaultValue) {
        if (isEmpty(o)) {
            return defaultValue;
        }
        return NumberUtils.toDouble(o.toString(), defaultValue);
    }

    public static Integer getNutNullInteger(Object o, Integer defaultValue) {
        if (isEmpty(o)) {
            return defaultValue;
        }
        return NumberUtils.toInt(o.toString(), defaultValue);
    }

    public static String getNutNullStr(Object o) {
        return getNutNullStr(o, "");
    }


    /**
     * 获取子串,str可以是null
     */
    public static String getSubStr(String str, int maxLength) {
        return isEmpty(str) ? "" : str.length() > maxLength ? str.substring(0, maxLength) : str;
    }



    /**
     * 数据格式化.
     *
     * @param pattern the pattern
     *                //@param i
     *                the i
     * @return the string
     */
    public static String codeFormat(String pattern, Object value) {
        DecimalFormat df = new DecimalFormat(pattern);
        return df.format(value);
    }

    /**
     * 格式化金额.
     *
     * @param value the value
     * @return the string
     */
    public static String formatCurrency2String(Long value) {
        if (value == null || "0".equals(String.valueOf(value))) {
            return "0.00";
        }
        DecimalFormat df = new DecimalFormat("0.00");
        return df.format(value / 100.00);
    }

    /**
     * 格式化金额.
     *
     * @param priceFormat the price format
     * @return the long
     */
    public static Long formatCurrency2Long(String priceFormat) {
        BigDecimal bg = new BigDecimal(priceFormat);
        Long price = bg.multiply(new BigDecimal(100)).longValue();
        return price;
    }

    /**
     * 去除html标签
     *
     * @param htmlStr
     * @return
     */
    @SuppressWarnings("all")
    public static String delHTMLTag(String htmlStr) {
        String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
        String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
        String regEx_html = "<[^>]+>"; //定义HTML标签的正则表达式
        Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
        Matcher m_script = p_script.matcher(htmlStr);
        htmlStr = m_script.replaceAll(""); //过滤script标签
        Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
        Matcher m_style = p_style.matcher(htmlStr);
        htmlStr = m_style.replaceAll(""); //过滤style标签
        Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
        Matcher m_html = p_html.matcher(htmlStr);
        htmlStr = m_html.replaceAll(""); //过滤html标签
        return htmlStr.trim(); //返回文本字符串
    }


    /**
     * 将xml字符串转化为实体对象
     *
     * @param <T>
     * @param xml
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T xml2bean(String xml, Class<T> clazz) {
        T t = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            t = (T) unmarshaller.unmarshal(new StringReader(xml));

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        return t;
    }


    /**
     * 数字转成字符，如1-->A;2--->B...
     *
     * @param num
     * @return
     */
    public static char aaNumToChar(int num) {
        return (char) (64 + num);
    }

    /**
     * 获取字符的键盘值
     *
     * @param s
     * @return
     */
    private static Integer aaCharToNum(char s) {
        Integer result = 0;
        switch (s) {
            case 'A':
                result = 65;
                break;
            case 'B':
                result = 66;
                break;
            case 'C':
                result = 67;
                break;
            case 'D':
                result = 68;
                break;
            case 'E':
                result = 69;
                break;
            case 'F':
                result = 70;
                break;
            case 'G':
                result = 71;
                break;
            case 'H':
                result = 72;
                break;
            case 'I':
                result = 73;
                break;
            case 'J':
                result = 74;
                break;
            case 'K':
                result = 75;
                break;
            case 'L':
                result = 76;
                break;
            case 'M':
                result = 77;
                break;
            case 'N':
                result = 78;
                break;
            case 'O':
                result = 79;
                break;
            case 'P':
                result = 80;
                break;
            case 'Q':
                result = 81;
                break;
            case 'R':
                result = 82;
                break;
            case 'S':
                result = 83;
                break;
            case 'T':
                result = 84;
                break;
            case 'U':
                result = 85;
                break;
            case 'V':
                result = 86;
                break;
            case 'W':
                result = 87;
                break;
            case 'X':
                result = 88;
                break;
            case 'Y':
                result = 89;
                break;
            case 'Z':
                result = 90;
                break;
            case 'a':
                result = 97;
                break;
            case 'b':
                result = 98;
                break;
            case 'c':
                result = 99;
                break;
            case 'd':
                result = 100;
                break;
            case 'e':
                result = 101;
                break;
            case 'f':
                result = 102;
                break;
            case 'g':
                result = 103;
                break;
            case 'h':
                result = 104;
                break;
            case 'i':
                result = 105;
                break;
            case 'j':
                result = 106;
                break;
            case 'k':
                result = 107;
                break;
            case 'l':
                result = 108;
                break;
            case 'm':
                result = 109;
                break;
            case 'n':
                result = 110;
                break;
            case 'o':
                result = 111;
                break;
            case 'p':
                result = 112;
                break;
            case 'q':
                result = 113;
                break;
            case 'r':
                result = 114;
                break;
            case 's':
                result = 115;
                break;
            case 't':
                result = 116;
                break;
            case 'u':
                result = 117;
                break;
            case 'v':
                result = 118;
                break;
            case 'w':
                result = 119;
                break;
            case 'x':
                result = 120;
                break;
            case 'y':
                result = 121;
                break;
            case 'z':
                result = 122;
                break;
            case '0':
                result = 48;
                break;
            case '1':
                result = 49;
                break;
            case '2':
                result = 50;
                break;
            case '3':
                result = 51;
                break;
            case '4':
                result = 52;
                break;
            case '5':
                result = 53;
                break;
            case '6':
                result = 54;
                break;
            case '7':
                result = 55;
                break;
            case '8':
                result = 56;
                break;
            case '9':
                result = 57;
                break;
            default:
                result = 0;
        }
        return result;
    }

    /**
     * 如 excel 里面显示
     * 递归问题--数字转化为字母，如(0-A,1-B....25-Z, 26-AA...)
     *
     * @param i
     * @return
     */
    public static String aaMoreNumToChar(int i) {
        if ((0 <= i) && (i <= 25)) {
            i += 65;
            char ch = (char) i;
            return String.valueOf(ch);
        } else {
            return aaMoreNumToChar(i / 26 - 1) + aaMoreNumToChar(i % 26);
        }
    }

    /**
     * excel 里面显示
     * <p>
     * A->0; B->1;...AA->26
     *
     * @param value
     * @return
     */
    public static int aaMoreCharToNum(String value) {
        int rtn = 0;
        int powIndex = 0;
        value = value.toUpperCase();
        for (int i = value.length() - 1; i >= 0; i--) {
            int tmpInt = value.charAt(i);
            tmpInt -= 64;

            rtn += (int) Math.pow(26, powIndex) * tmpInt;
            powIndex++;
        }
        //数值减去1
        rtn = rtn > 0 ? rtn - 1 : 0;
        return rtn;
    }





    public static String dealMobileStr(String mobileOldStr) {
        if (isEmpty(mobileOldStr)) {
            return null;
        }
        String str = mobileOldStr.replace("-", "").trim().replace(" ", "");
        if (str.length() > 11) {
            str = str.substring(11);
        }
        return str;
    }

    public static boolean isEmpty(String text) {
        return StringUtils.isEmpty(text);
    }

    /**
     * 判断是否为空和isEmpty类似，只是如果输入的内容是空白符号，如：\t \n \f \r 空格等，均视为空
     *
     * @param text
     * @return
     */
    public static boolean isBlank(String text) {
        return StringUtils.isBlank(text);
    }

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


    /**
     * 获取文件后缀.
     * 不包含.
     * <p>
     * 如：/Users/duandazhi/Desktop/360.exe  ---> exe
     * <p>
     * FilenameUtils.getExtension(file.getOriginalFilename())
     */
    public static String getFileSuffix(String name) {
        if (name == null) {
            return "";
        }
        if (name.indexOf(".") == -1) {
            return "";
        }

        String suffix = name.substring(name.lastIndexOf(".") + 1);

        return suffix.trim().toLowerCase();
    }

    public static String getFileExt(String name) {
        return getFileSuffix(name);
    }

    public static String getFileExtentsion(MultipartFile file) {
        return FilenameUtils.getExtension(file.getOriginalFilename());
    }

    /**
     * 获取文件名称
     *
     * @param path
     * @return 如：path http://dl.360safe.com/360zip_setup_4.0.0.1050.exe --- > 360zip_setup_4.0.0.1050.exe
     */
    public static String getFileNames(String path) {
        return getFileNames(path, "/");
    }

    public static String getFileNames(String path, String regex) {
        if (path == null || path.equalsIgnoreCase("")) {
            return "";
        }
        String[] paths = path.split(regex);
        if (paths.length != 0) {
            return paths[paths.length - 1];
        }
        return "";
    }

    /**
     * /Users/duandazhi/Desktop/360.exe  变成  UsersduandazhiDesktop360.exe
     *
     * @param path
     * @return
     */
    public static String getFileName(String path) {
        String result = "";
        if (StringUtils.isNotBlank(path)) {
            result = path.replace("*", "").replace("|", "")
                    .replace("\\", "").replace(":", "")
                    .replace(">", "")
                    .replace("?", "")
                    .replace("<", "")
                    .replace("/", "").replace("\"", "");
        }
        return result;
    }


    /**
     * os.name:
     * windows or mac os x or mac os or linux
     *
     * @see
     */
    public static boolean isWindows() {
        String osName = System.getProperty("os.name", "windows").toLowerCase();
        if (osName.contains("windows")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * linux:   file:/work/android-project/
     * windows: file:\\work\\android-project\\
     *
     * @return
     */
    public static String parseFilePath(String path) {
        if (path == null || path.trim().length() == 0) {
            return "";
        }
        if (isWindows()) {
            if (!path.contains("\\\\")) {
                return path.replaceAll("/", "\\\\");
            } else {
                return path;
            }
        } else {
            if (!path.contains("/")) {
                return path.replaceAll("\\\\", "/");
            } else {
                return path;
            }
        }
    }



    /**
     * 金额转换,小写金钱转出大写;
     * 数字转换为汉语中人民币的大写
     * eg:98.76 -->  玖拾捌元柒角陆分
     * eg:12345678.9 -->  壹千贰佰叁拾肆万伍千陆佰柒拾捌元玖角整
     *
     * @param v
     * @return
     */
    public static String moneyTransform(double v) {
        if (Math.abs(v) > XaUtils.MAX_VALUE) {
            return "参数非法!";
        }
        boolean isNegative = false;
        if (v < 0) {
            isNegative = true;
            v = Math.abs(v);
        }
        long l = Math.round(v * 100);
        if (l == 0) {
            return "零元整";
        }
        String strValue = l + "";
        // i用来控制数
        int i = 0;
        // j用来控制单位
        int j = UNIT.length() - strValue.length();
        String rs = "";
        boolean isZero = false;
        for (; i < strValue.length(); i++, j++) {
            char ch = strValue.charAt(i);
            if (ch == '0') {
                isZero = true;
                if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') {
                    rs = rs + UNIT.charAt(j);
                    isZero = false;
                }
            } else {
                if (isZero) {
                    rs = rs + "零";
                    isZero = false;
                }
                rs = rs + DIGIT.charAt(ch - '0') + UNIT.charAt(j);
            }
        }
        if (!rs.endsWith("分")) {
            rs = rs + "整";
        }
        rs = rs.replaceAll("亿万", "亿");
        rs = (isNegative ? "负" : "") + rs;
        return rs;
    }



    /**
     * map抓换为xml报文
     * 手工处理，没有xml头
     *
     * @param map
     * @param sb
     */
    @SuppressWarnings("all")
    public static String mapToXML2(Map map, StringBuilder sb) {
        Set set = map.keySet();
        for (Iterator it = set.iterator(); it.hasNext(); ) {
            String key = (String) it.next();
            Object value = map.get(key);
            if (null == value) {
                value = "";
            }
            if (value instanceof List) {
                ArrayList list = (ArrayList) map.get(key);
                sb.append("<" + key + ">");
                for (int i = 0; i < list.size(); i++) {
                    HashMap hm = (HashMap) list.get(i);
                    mapToXML2(hm, sb);
                }
                sb.append("</" + key + ">");

            } else {
                if (value instanceof Map) {
                    sb.append("<" + key + ">");
                    mapToXML2((HashMap) value, sb);
                    sb.append("</" + key + ">");
                } else {
                    sb.append("<" + key + ">" + value + "</" + key + ">");
                }
            }
        }
        return sb.toString();
    }






    /**
     * Java字符串跟ASCII码互转
     * http://www.cnblogs.com/fengwenzhee/p/7239822.html
     * string -> Ascii
     *
     * @param value
     * @return <code>
     * String str = "{name:1234,password:4444}";
     * String asciiResult = stringToAscii(str.trim());
     * System.out.println(asciiResult);
     * String stringResult = asciiToString(asciiResult);
     * System.out.println(stringResult);
     * System.out.println(asciiToString("160").trim()+"~");
     * System.out.println( asciiToString("10"));
     * System.out.println( asciiToString("10"));
     * System.out.println("....");
     * </code>
     * https://www.sojson.com/ascii.html
     * A -- 65
     * a -- 97
     * a -- 97
     * 空格 -- 32
     * 回车 -- 10
     */
    public static String stringToAscii(String value) {
        StringBuffer sbu = new StringBuffer();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (i != chars.length - 1) {
                sbu.append((int) chars[i]).append(",");
            } else {
                sbu.append((int) chars[i]);
            }
        }
        return sbu.toString();
    }

    /**
     * Ascii -> string
     *
     * @param value
     * @return
     */
    public static String asciiToString(String value) {
        StringBuffer sbu = new StringBuffer();
        String[] chars = value.split(",");
        for (int i = 0; i < chars.length; i++) {
            sbu.append((char) Integer.parseInt(chars[i]));
        }
        return sbu.toString();
    }


    /**
     * 去重空格，包含：空格、tab键、换行、&nbsp;
     * 这里比较系统的多了一个 &nbsp;
     * 分别是：32、9、10、160
     * <p>
     * Trim leading and trailing whitespace from the given {@code String}.
     *
     * @param str the {@code String} to check
     * @return the trimmed {@code String}
     * @see Character#isWhitespace + &nbsp;
     * <p>
     * <p>
     * 一般的空白符默认值的 空格、tab键、换行符
     * 这里的空白符默认值的 ' '、\t、   \n   、&nbps 四种空白符
     * https://www.sojson.com/ascii.html
     * 特殊的空格-ASCII码值160 和 32 是对应的两种空格 https://blog.csdn.net/lewky_liu/article/details/79353151
     * <p>
     * 示例：
     * <code>
     * char cc = 160;
     * String aa = cc +  " 我是测试字符串\n\t";
     * System.out.println();
     * System.out.println(aa);
     * System.out.println("length:" + aa.length());
     * System.out.println(XaUtils.trimContainNbsp(aa));
     * System.out.println(aa.trim());
     * System.out.println();
     * </code>
     */
    public static String trim(String str) {
        str = str.trim() + "";
        str = org.springframework.util.StringUtils.trimTrailingCharacter(str, (char) 160);
        str = str.trim();
        str = org.springframework.util.StringUtils.trimLeadingCharacter(str, (char) 160);
        str = str.trim();
        return str;
    }

    /**
     * 去处科学技术法
     *
     * @see #
     * 如何准确的将科学计数法表示的Double类型转换为正常的字符串？
     * https://segmentfault.com/q/1010000008823954
     * <code>
     * double a = 123456729.326666;
     * System.out.println(a);
     * System.out.println(Validator.isScientificCountingMethod("1.23456729326666E8"));
     * System.out.println(Validator.isScientificCountingMethod("142342xd"));
     * System.out.println(XaUtils.bigdecimalPlaninString(a));
     * double a = 123456729.326666;
     * System.out.println(a);
     * System.out.println(Validator.isScientificCountingMethod("1.23456729326666E8"));
     * System.out.println(Validator.isScientificCountingMethod("142342xd"));
     * System.out.println(XaUtils.bigdecimalPlaninString(a));
     * </code>
     * double 本来就有精度，必须指定保留多少位小数
     * 比如，excel 里面是数字，项目里面对应的字段是字符串，就容易出现科学技术法
     */
    public static String bigdecimalPlaninString(double d) {
        BigDecimal d1 = new BigDecimal(Double.toString(d));
        BigDecimal d2 = new BigDecimal(Integer.toString(1));
        // 四舍五入,保留10位小数
        BigDecimal bigDecimal = d1.divide(d2, 20, BigDecimal.ROUND_HALF_UP);
        // 这里在去掉，小数点收无用的0
        return bigDecimal.stripTrailingZeros().toPlainString();
    }


    /**
     * 使用java正则表达式去掉多余的.与0
     * <code>
     * double aaa = 131432.0;
     * double aab = 131432.00000;
     * double bbb = 131432;
     * double bbc = 131432.143243;
     * System.out.println(aaa);
     * System.out.println(bbb);
     * System.out.println(aab);
     * System.out.println(String.valueOf(bbb));
     * System.out.println(new BigDecimal(bbc).stripTrailingZeros().toPlainString());
     * <p>
     * //double 直接使用 sout 输出，总是 自带一位小数，这里进行处理
     * </code>
     *
     * @param s
     * @return
     */
    public static String subZeroAndDot(String s) {
        if (s.indexOf(".") > 0) {
            //去掉多余的0
            s = s.replaceAll("0+?$", "");
            //如最后一位是.则去掉
            s = s.replaceAll("[.]$", "");
        }
        return s;
    }

    /**
     * 解析地址 快递地址信息
     * https://blog.csdn.net/superSubfn/article/details/80290491
     *
     * @param address
     * @return
     * @author lin
     * <p>
     * <p>
     * System.out.println(addressResolution("湖北省武汉市洪山区"));
     * System.out.println(addressResolution("湖北省武汉市洪山区"));
     * System.out.println(addressResolution("湖北省恩施土家族苗族自治州恩施市"));
     * System.out.println(addressResolution("北京市市辖区朝阳区"));
     * System.out.println(addressResolution("内蒙古自治区兴安盟科尔沁右翼前旗"));
     * System.out.println(addressResolution("西藏自治区日喀则地区日喀则市"));
     * System.out.println(addressResolution("海南省省直辖县级行政单位中沙群岛的岛礁及其海域"));
     * System.out.println(addressResolution("陕西省西安市雁塔区旺座现代城E座1004"));
     */
    public static List<Map<String, String>> expressAddressResolution(String address) {
        String regex = "(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<village>.*)";
        Matcher m = Pattern.compile(regex).matcher(address);
        String province = null, city = null, county = null, town = null, village = null;
        List<Map<String, String>> table = new ArrayList<Map<String, String>>();
        Map<String, String> row = null;
        while (m.find()) {
            row = new LinkedHashMap<String, String>();
            province = m.group("province");
            row.put("province", province == null ? "" : province.trim());
            city = m.group("city");
            row.put("city", city == null ? "" : city.trim());
            county = m.group("county");
            row.put("county", county == null ? "" : county.trim());
            town = m.group("town");
            row.put("town", town == null ? "" : town.trim());
            village = m.group("village");
            row.put("village", village == null ? "" : village.trim());
            table.add(row);
        }
        return table;
    }

}
