All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wl4g.infra.common.lang.StringUtils2 Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 ~ 2025 the original author or authors. James Wong 
 *
 * 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 com.wl4g.infra.common.lang;

import static com.google.common.base.Charsets.UTF_8;
import static com.wl4g.infra.common.lang.Assert2.hasTextOf;
import static java.lang.String.valueOf;
import static java.util.Objects.isNull;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringEscapeUtils;

import com.google.common.collect.Lists;
import com.wl4g.infra.common.collection.CollectionUtils2;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.SuperBuilder;

/**
 * String Tools.
 * 
 * @author James Wong
 * @version 2017-05-28
 * @since v3.0.0
 */
public abstract class StringUtils2 extends org.apache.commons.lang3.StringUtils {
    private static final String FOLDER_SEPARATOR = "/";
    private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
    private static final String TOP_PATH = "..";
    private static final String CURRENT_PATH = ".";
    private static final char EXTENSION_SEPARATOR = '.';
    private static final char SEPARATOR = '_';

    private static final String REGEX_IS_MAIL = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
    private static final String REGEX_IS_NUMBER = "^[0-9]*$";
    private static final String REGEX_IS_DECIMALS = "([1-9]+[0-9]*|0)(\\.[\\d]+)?";
    private static final String REGEX_IS_IP = "\\b((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])"
            + "\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d"
            + "\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\b";
    /// DNS规定,域名中的标号都由英文字母和数字组成,每一个标号不超过63个字符,也不区分大小写字母。标号中除连字符(-)外不能使用其他的标点符号。级别最低的域名写在最左边,而级别最高的域名写在最右边。由多个标号组成的完整域名总共不超过255个字符。
    private static final String REGEX_DOMAIN = "^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$";
    private static final String REGEX_URL = "^((http|ftp|https)://)(([a-zA-Z0-9\\._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\\&%_\\./-~-]*)?$";

    private static final String CHINESE_REGEX = "[\u4e00-\u9fa5]+";
    private static final Pattern patternChinese = Pattern.compile(CHINESE_REGEX);
    private static final Pattern patternLetter = Pattern.compile("[A-Za-z]");

    public static byte[] getBytes(@Nullable String str) {
        if (isBlank(str)) {
            return null;
        }
        return !isBlank(str) ? str.getBytes(UTF_8) : null;
    }

    public static String toString(@Nullable byte[] bytes) {
        if (isNull(bytes)) {
            return null;
        }
        return new String(bytes, UTF_8);
    }

    /**
     * whether to contain a string
     * 
     * @param str
     *            验证字符串
     * @param strs
     *            字符串组
     * @return 包含返回true
     */
    public static boolean inString(@Nullable String str, String... strs) {
        if (str != null) {
            for (String s : strs) {
                if (str.equals(trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Replace the HTML tag method
     */
    public static String replaceHtml(@Nullable String html) {
        if (isBlank(html)) {
            return "";
        }
        String regEx = "<.+?>";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(html);
        String s = m.replaceAll("");
        return s;
    }

    /**
     * 替换为手机识别的HTML,去掉样式及属性,保留回车。
     * 
     * @param html
     * @return
     */
    public static String replaceMobileHtml(String html) {
        if (html == null) {
            return "";
        }
        return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>");
    }

    /**
     * 缩略字符串(不区分中英文字符)
     * 
     * @param str
     *            目标字符串
     * @param length
     *            截取长度
     * @return
     */
    public static String abbr(String str, int length) {
        if (str == null) {
            return "";
        }
        try {
            StringBuilder sb = new StringBuilder();
            int currentLength = 0;
            for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) {
                currentLength += String.valueOf(c).getBytes("GBK").length;
                if (currentLength <= length - 3) {
                    sb.append(c);
                } else {
                    sb.append("...");
                    break;
                }
            }
            return sb.toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }

    public static String abbr2(String param, int length) {
        if (param == null) {
            return "";
        }
        StringBuffer result = new StringBuffer();
        int n = 0;
        char temp;
        boolean isCode = false; // 是不是HTML代码
        boolean isHTML = false; // 是不是HTML特殊字符,如 
        for (int i = 0; i < param.length(); i++) {
            temp = param.charAt(i);
            if (temp == '<') {
                isCode = true;
            } else if (temp == '&') {
                isHTML = true;
            } else if (temp == '>' && isCode) {
                n = n - 1;
                isCode = false;
            } else if (temp == ';' && isHTML) {
                isHTML = false;
            }
            try {
                if (!isCode && !isHTML) {
                    n += String.valueOf(temp).getBytes("GBK").length;
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            if (n <= length - 3) {
                result.append(temp);
            } else {
                result.append("...");
                break;
            }
        }
        // 取出截取字符串中的HTML标记
        String temp_result = result.toString().replaceAll("(>)[^<>]*(]*/?>",
                "");
        // 去掉成对的HTML标记
        temp_result = temp_result.replaceAll("<([a-zA-Z]+)[^<>]*>(.*?)", "$2");
        // 用正则表达式取出标记
        Pattern p = Pattern.compile("<([a-zA-Z]+)[^<>]*>");
        Matcher m = p.matcher(temp_result);
        List endHTML = Lists.newArrayList();
        while (m.find()) {
            endHTML.add(m.group(1));
        }
        // 补全不成对的HTML标记
        for (int i = endHTML.size() - 1; i >= 0; i--) {
            result.append("");
        }
        return result.toString();
    }

    /**
     * 转换为Double类型
     */
    public static Double toDouble(Object val) {
        if (val == null) {
            return 0D;
        }
        try {
            return Double.valueOf(trim(val.toString()));
        } catch (Exception e) {
            return 0D;
        }
    }

    /**
     * 转换为Float类型
     */
    public static Float toFloat(Object val) {
        return toDouble(val).floatValue();
    }

    /**
     * 转换为Long类型
     */
    public static Long toLong(Object val) {
        return toDouble(val).longValue();
    }

    /**
     * 转换为Integer类型
     */
    public static Integer toInteger(Object val) {
        return toLong(val).intValue();
    }

    /**
     * 获得用户远程地址
     */
    public static String getRemoteAddr(HttpServletRequest request) {
        String remoteAddr = request.getHeader("X-Real-IP");
        if (isNotBlank(remoteAddr)) {
            remoteAddr = request.getHeader("X-Forwarded-For");
        } else if (isNotBlank(remoteAddr)) {
            remoteAddr = request.getHeader("Proxy-Client-IP");
        } else if (isNotBlank(remoteAddr)) {
            remoteAddr = request.getHeader("WL-Proxy-Client-IP");
        }
        return remoteAddr != null ? remoteAddr : request.getRemoteAddr();
    }

    /**
     * 驼峰命名法工具
     * 
     * @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 toCapitalizeCamelCase(String s) {
        if (s == null) {
            return null;
        }
        s = toCamelCase(s);
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }

    /**
     * 驼峰命名法工具
     * 
     * @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();
    }

    /**
     * 如果不为空,则设置值
     * 
     * @param target
     * @param source
     */
    public static void setValueIfNotBlank(String target, String source) {
        if (isNotBlank(source)) {
            target = source;
        }
    }

    /**
     * 转换为JS获取对象值,生成三目运算返回结果
     * 
     * @param objectString
     *            对象串 例如:row.user.id
     *            返回:!row?'':!row.user?'':!row.user.id?'':row.user.id
     */
    public static String jsGetVal(String objectString) {
        StringBuilder result = new StringBuilder();
        StringBuilder val = new StringBuilder();
        String[] vals = split(objectString, ".");
        for (int i = 0; i < vals.length; i++) {
            val.append("." + vals[i]);
            result.append("!" + (val.substring(1)) + "?'':");
        }
        result.append(val.substring(1));
        return result.toString();
    }

    /**
     * Checks if a CharSequence is empty ("") or null.
* StringUtils.isEmpty("null") = true
* StringUtils.isEmpty("NULL") = true
* StringUtils.isEmpty(null) = true
* StringUtils.isEmpty("") = true
* StringUtils.isEmpty(" ") = false
* StringUtils.isEmpty("bob") = false
* StringUtils.isEmpty(" bob ") = false
* * @param object * target object * @return true if the CharSequence is empty or null */ public static boolean isEmpty(Object object) { if (object == null || eqIgnCase(object, "null")) { return true; } else if (object instanceof CharSequence) { return isEmpty(object.toString()); } return false; } /** *

全部为空才返回 TRUE


*
  • 如果有一个不为空则返回false, (即不是所有都为空)
  • * * @param objectlist * 目标对象 * @return 是否为空(包括空对象、空字符串、null等) */ public static boolean isAllEmpty(Object... objectlist) { if (objectlist == null) { return true; } for (Object obj : objectlist) { if (!isEmpty(obj)) { return false; } } return true; } /** *

    存在任何一个(只要有一个)为空就返回 TRUE


    * * @param objectlist * 目标对象 * @return 是否为空(包括空对象、空字符串、null等) */ public static boolean isAnyEmpty(Object... objectlist) { if (objectlist == null) { return true; } for (Object obj : objectlist) { if (isEmpty(obj)) { return true; } } return false; } /** * 全部不为空才返回 TRUE * * @param objectlist * @return */ public static boolean isNotAllEmpty(Object... objectlist) { return !isAnyEmpty(objectlist); } /** * 存在任何一个(至少一个)不为空则返回 TRUE * * @param objectlist * @return */ public static boolean isNotAnyEmpty(Object... objectlist) { return !isAllEmpty(objectlist) && !isNotAllEmpty(objectlist) || isNotAllEmpty(objectlist); } /** * Equals for objects. * * @param obj1 * @param obj2 * @return */ public static boolean eqIgnCase(Object obj1, Object obj2) { if (obj1 == null && obj2 == null) { return true; } if (equalsIgnoreCase(valueOf(obj1).toString(), valueOf(obj2).toString())) { return true; } return false; } /** * 是否存在中文, 只要有一个中文字符就返回TRUE * * @param str * @return */ public static boolean isAnyChinese(String str) { return matcheAny(patternChinese, str); // 是否含有中文字符 } /** * 全部时中文才返回TRUE * * @param str * @return */ public static boolean isAllChinese(String str) { return matchesAll(CHINESE_REGEX, str); // 是否全是中文字符 } /** * 是否全部为字母 * * @param str * @return */ public static boolean isAllLetter(String str) { return matchesAll("^[A-Za-z]+$", str); // 是否全是字母构成 } /** * 是否包含字母 * * @param str * @return */ public static boolean isAnyLetter(String str) { return matcheAny(patternLetter, str); // 是否全是字母构成 } /** * Calculate the corresponding numerical result according to the string * expression
    * e.: StringUtil.calculate("3 * (10 % 3 + 2) / 2") => 4 * * @param expr * @throws RuntimeException */ public static String calculate(String expr) throws RuntimeException { if (isEmpty(expr)) { throw new NullPointerException("表达式expStr不能为空."); } Object result = null; try { result = SimpleMathExpressions.calculate(expr); } catch (Exception e) { e.printStackTrace(); } return result == null ? null : result.toString(); } /** * Computes the corresponding numeric result based on a string expression *
    * 例: System.out.println(StringUtil.calculate("3 > (10 % 3 + 2) / 2")); ==> * false
    * 例: System.out.println(StringUtil.calculate("3 <= (10 % 3 + 2) / 2")); ==> * true * * @param expStr * 字符串boolean表达式 * @return 返回检测结果 * @throws RuntimeException */ public static Boolean test(@NotBlank String expStr) throws RuntimeException { hasTextOf(expStr, "expStr"); Boolean result = null; try { result = SimpleMathExpressions.test(expStr); } catch (Exception e) { throw new IllegalStateException(e); } return result == null ? null : result; } public static boolean matchesAll(@Nullable String str, @NotBlank String regex) { hasTextOf(regex, "regex"); if (isBlank(str)) { return false; } try { str = new String(str.getBytes(), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException(e); } return str.matches(regex); } public static boolean matcheAny(Pattern pattern, String str) { try { str = new String(str.getBytes(), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return pattern.matcher(str).find(); } /** * Check if it is not a number * * @param str * @return */ public static boolean isNaN(String str) { return str.matches(REGEX_IS_NUMBER); } public static boolean isDecimal(String str) { return str.matches(REGEX_IS_DECIMALS); } public static boolean isMail(String str) { return str.matches(REGEX_IS_MAIL); } /** * 校验是否可符合IP 规则 * * @param str * 待验证字符串 * @return 是否是合法IP 格式 */ public static boolean isIP(String str) { return str.matches(REGEX_IS_IP); } /** * Validate is URL * * @param url * @return */ public static boolean isURL(String url) { if (isBlank(url)) { return false; } return url.matches(REGEX_URL); } /** * Validate is domain * * @param domain * @return */ public static boolean isDomain(String domain) { if (isBlank(domain)) { return false; } return domain.matches(REGEX_DOMAIN) || domain.equalsIgnoreCase("localhost"); } /** * Mutilate JSON message parse.
    * 终端可能会同时输入多个数据包, eg: 业务数据包 + 心跳H * * @param msg * @return */ public static List unpackingMessage(String msg) { msg = (String.valueOf(msg)).replaceAll("\r\n", "").replaceAll("\n", ""); // 否则会执行到dispatcher方法产生异常 List msgBufs = new ArrayList(); char[] chars = msg.toCharArray(); StringBuffer sb = new StringBuffer(); int leftQuote = 0; for (int i = 0; i < chars.length; i++) { if (chars[i] == '{') { leftQuote++; sb.append(chars[i]); continue; } if (chars[i] == '}') { leftQuote--; sb.append(chars[i]); if (leftQuote == 0) { msgBufs.add(sb.toString()); sb.setLength(0); } continue; } if (leftQuote > 0) { sb.append(chars[i]); continue; } msgBufs.add(String.valueOf(chars[i])); } return msgBufs; } /** * Extract the filename from the given Java resource path, e.g. * {@code "mypath/myfile.txt" -> "myfile.txt"}. * * @param path * the file path (may be {@code null}) * @return the extracted filename, or {@code null} if none */ public static String getFilename(String path) { if (path == null) { return null; } int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); } /** * Extract the filename extension from the given Java resource path, e.g. * "mypath/myfile.txt" -> "txt". * * @param path * the file path (may be {@code null}) * @return the extracted filename extension, or {@code null} if none */ public static String getFilenameExtension(String path) { if (path == null) { return null; } int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); if (extIndex == -1) { return null; } int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); if (folderIndex > extIndex) { return null; } return path.substring(extIndex + 1); } /** * Is true
    * * @param value * @return Return TRUE with true/t/y/yes/on/1/enabled */ public static boolean isTrue(String value) { return isTrue(value, false); } /** * Is true
    * * @param value * @param defaultValue * @return Return TRUE with true/t/y/yes/on/1/enabled */ public static boolean isTrue(String value, boolean defaultValue) { if (isBlank(value)) { return defaultValue; } return (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("t") || value.equalsIgnoreCase("1") || value.equalsIgnoreCase("enabled") || value.equalsIgnoreCase("y") || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("on")); } // --- Spring StringUtils. --- /** * Take an array of strings and split each element based on the given * delimiter. A {@code Properties} instance is then generated, with the left * of the delimiter providing the key, and the right of the delimiter * providing the value. *

    * Will trim both the key and value before adding them to the * {@code Properties}. * * @param array * the array to process * @param delimiter * to split each element using (typically the equals symbol) * @return a {@code Properties} instance representing the array contents, or * {@code null} if the array to process was {@code null} or empty */ public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { return splitArrayElementsIntoProperties(array, delimiter, null); } /** * Take an array of strings and split each element based on the given * delimiter. A {@code Properties} instance is then generated, with the left * of the delimiter providing the key, and the right of the delimiter * providing the value. *

    * Will trim both the key and value before adding them to the * {@code Properties} instance. * * @param array * the array to process * @param delimiter * to split each element using (typically the equals symbol) * @param charsToDelete * one or more characters to remove from each element prior to * attempting the split operation (typically the quotation mark * symbol), or {@code null} if no removal should occur * @return a {@code Properties} instance representing the array contents, or * {@code null} if the array to process was {@code null} or empty */ public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter, String charsToDelete) { if (ObjectUtils2.isEmpty(array)) { return null; } Properties result = new Properties(); for (String element : array) { if (charsToDelete != null) { element = deleteAny(element, charsToDelete); } String[] splittedElement = split(element, delimiter); if (splittedElement == null) { continue; } result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); } return result; } /** * Tokenize the given {@code String} into a {@code String} array via a * {@link StringTokenizer}. *

    * Trims tokens and omits empty tokens. *

    * The given {@code delimiters} string can 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 {@link #delimitedListToStringArray}. * * @param str * the {@code String} to tokenize * @param delimiters * the delimiter characters, assembled as a {@code String} (each * of the characters is individually considered as a 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 {@code String} into a {@code String} array via a * {@link StringTokenizer}. *

    * The given {@code delimiters} string can 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 {@link #delimitedListToStringArray}. * * @param str * the {@code String} to tokenize * @param delimiters * the delimiter characters, assembled as a {@code String} (each * of the characters is individually considered as a delimiter) * @param trimTokens * trim the tokens via {@link String#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 * @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 tokens = new ArrayList(); while (st.hasMoreTokens()) { String token = st.nextToken(); if (trimTokens) { token = token.trim(); } if (!ignoreEmptyTokens || token.length() > 0) { tokens.add(token); } } return toStringArray(tokens); } /** * Take a {@code String} that is a delimited list and convert it into a * {@code String} array. *

    * A single {@code delimiter} may consist of more than one character, but it * will still be considered as a single delimiter string, rather than as * bunch of potential delimiter characters, in contrast to * {@link #tokenizeToStringArray}. * * @param str * the input {@code String} * @param delimiter * the delimiter between elements (this is a single delimiter, * rather than a bunch individual delimiter characters) * @return an array of the tokens in the list * @see #tokenizeToStringArray */ public static String[] delimitedListToStringArray(String str, String delimiter) { return delimitedListToStringArray(str, delimiter, null); } /** * Take a {@code String} that is a delimited list and convert it into a * {@code String} array. *

    * A single {@code delimiter} may consist of more than one character, but it * will still be considered as a single delimiter string, rather than as * bunch of potential delimiter characters, in contrast to * {@link #tokenizeToStringArray}. * * @param str * the input {@code String} * @param delimiter * the delimiter between elements (this is a single delimiter, * rather than a bunch individual delimiter characters) * @param charsToDelete * a set of characters to delete; useful for deleting unwanted * line breaks: e.g. "\r\n\f" will delete all new lines and line * feeds in a {@code String} * @return an array of the tokens in the list * @see #tokenizeToStringArray */ public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { if (str == null) { return new String[0]; } if (delimiter == null) { return new String[] { str }; } List result = new ArrayList(); if ("".equals(delimiter)) { for (int i = 0; i < str.length(); i++) { result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); } } else { int pos = 0; int delPos; while ((delPos = str.indexOf(delimiter, pos)) != -1) { result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); pos = delPos + delimiter.length(); } if (str.length() > 0 && pos <= str.length()) { // Add rest of String, but not in case of empty input. result.add(deleteAny(str.substring(pos), charsToDelete)); } } return toStringArray(result); } /** * Convert a comma delimited list (e.g., a row from a CSV file) into an * array of strings. * * @param str * the input {@code String} * @return an array of strings, or the empty array in case of empty input */ public static String[] commaDelimitedListToStringArray(String str) { return delimitedListToStringArray(str, ","); } /** * Convert a comma delimited list (e.g., a row from a CSV file) into a set. *

    * Note that this will suppress duplicates, and as of 4.2, the elements in * the returned set will preserve the original order in a * {@link LinkedHashSet}. * * @param str * the input {@code String} * @return a set of {@code String} entries in the list * @see #removeDuplicateStrings(String[]) */ public static Set commaDelimitedListToSet(String str) { Set set = new LinkedHashSet(); String[] tokens = commaDelimitedListToStringArray(str); for (String token : tokens) { set.add(token); } return set; } /** * Convert a {@link Collection} to a delimited {@code String} (e.g. CSV). *

    * Useful for {@code toString()} implementations. * * @param coll * the {@code Collection} to convert * @param delim * the delimiter to use (typically a ",") * @param prefix * the {@code String} to start each element with * @param suffix * the {@code String} to end each element with * @return the delimited {@code String} */ public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { if (CollectionUtils2.isEmpty(coll)) { return ""; } StringBuilder sb = new StringBuilder(); Iterator it = coll.iterator(); while (it.hasNext()) { sb.append(prefix).append(it.next()).append(suffix); if (it.hasNext()) { sb.append(delim); } } return sb.toString(); } /** * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV). *

    * Useful for {@code toString()} implementations. * * @param coll * the {@code Collection} to convert * @param delim * the delimiter to use (typically a ",") * @return the delimited {@code String} */ public static String collectionToDelimitedString(Collection coll, String delim) { return collectionToDelimitedString(coll, delim, "", ""); } /** * Convert a {@code Collection} into a delimited {@code String} (e.g., CSV). *

    * Useful for {@code toString()} implementations. * * @param coll * the {@code Collection} to convert * @return the delimited {@code String} */ public static String collectionToCommaDelimitedString(Collection coll) { return collectionToDelimitedString(coll, ","); } /** * Convert a {@code String} array into a delimited {@code String} (e.g. * CSV). *

    * Useful for {@code toString()} implementations. * * @param arr * the array to display * @param delim * the delimiter to use (typically a ",") * @return the delimited {@code String} */ public static String arrayToDelimitedString(Object[] arr, String delim) { if (ObjectUtils2.isEmpty(arr)) { return ""; } if (arr.length == 1) { return ObjectUtils2.nullSafeToString(arr[0]); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { if (i > 0) { sb.append(delim); } sb.append(arr[i]); } return sb.toString(); } /** * Convert a {@code String} array into a comma delimited {@code String} * (i.e., CSV). *

    * Useful for {@code toString()} implementations. * * @param arr * the array to display * @return the delimited {@code String} */ public static String arrayToCommaDelimitedString(Object[] arr) { return arrayToDelimitedString(arr, ","); } /** * Check whether the given {@code CharSequence} contains any whitespace * characters. * * @param str * the {@code CharSequence} to check (may be {@code null}) * @return {@code true} if the {@code CharSequence} is not empty and * contains at least 1 whitespace character * @see Character#isWhitespace */ public static boolean containsWhitespace(CharSequence 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; } /** * Check whether the given {@code String} contains any whitespace * characters. * * @param str * the {@code String} to check (may be {@code null}) * @return {@code true} if the {@code String} is not empty and contains at * least 1 whitespace character * @see #containsWhitespace(CharSequence) */ public static boolean containsWhitespace(String str) { return containsWhitespace((CharSequence) str); } /** * Trim leading and trailing whitespace from the given {@code String}. * * @param str * the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimWhitespace(String str) { if (!hasLength(str)) { return str; } StringBuilder sb = new StringBuilder(str); while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { sb.deleteCharAt(0); } while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } /** * Trim all whitespace from the given {@code String}: leading, * trailing, and in between characters. * * @param str * the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimAllWhitespace(String str) { if (!hasLength(str)) { return str; } int len = str.length(); StringBuilder sb = new StringBuilder(str.length()); for (int i = 0; i < len; i++) { char c = str.charAt(i); if (!Character.isWhitespace(c)) { sb.append(c); } } return sb.toString(); } /** * Trim leading whitespace from the given {@code String}. * * @param str * the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimLeadingWhitespace(String str) { if (!hasLength(str)) { return str; } StringBuilder sb = new StringBuilder(str); while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { sb.deleteCharAt(0); } return sb.toString(); } /** * Trim trailing whitespace from the given {@code String}. * * @param str * the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimTrailingWhitespace(String str) { if (!hasLength(str)) { return str; } StringBuilder sb = new StringBuilder(str); while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } /** * Trim all occurrences of the supplied leading character from the given * {@code String}. * * @param str * the {@code String} to check * @param leadingCharacter * the leading character to be trimmed * @return the trimmed {@code String} */ public static String trimLeadingCharacter(String str, char leadingCharacter) { if (!hasLength(str)) { return str; } StringBuilder sb = new StringBuilder(str); while (sb.length() > 0 && sb.charAt(0) == leadingCharacter) { sb.deleteCharAt(0); } return sb.toString(); } /** * Trim all occurrences of the supplied trailing character from the given * {@code String}. * * @param str * the {@code String} to check * @param trailingCharacter * the trailing character to be trimmed * @return the trimmed {@code String} */ public static String trimTrailingCharacter(String str, char trailingCharacter) { if (!hasLength(str)) { return str; } StringBuilder sb = new StringBuilder(str); while (sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } /** * Test if the given {@code String} starts with the specified prefix, * ignoring upper/lower case. * * @param str * the {@code String} to check * @param prefix * the prefix to look for * @see java.lang.String#startsWith */ public static boolean startsWithIgnoreCase(String str, String prefix) { return (str != null && prefix != null && str.length() >= prefix.length() && str.regionMatches(true, 0, prefix, 0, prefix.length())); } /** * Test if the given {@code String} ends with the specified suffix, ignoring * upper/lower case. * * @param str * the {@code String} to check * @param suffix * the suffix to look for * @see java.lang.String#endsWith */ public static boolean endsWithIgnoreCase(String str, String suffix) { return (str != null && suffix != null && str.length() >= suffix.length() && str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length())); } /** * Test whether the given string matches the given substring at the given * index. * * @param str * the original string (or StringBuilder) * @param index * the index in the original string to start matching against * @param substring * the substring to match at the given index */ public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { if (index + substring.length() > str.length()) { return false; } for (int i = 0; i < substring.length(); i++) { if (str.charAt(index + i) != substring.charAt(i)) { return false; } } return true; } /** * Count the occurrences of the substring {@code sub} in string {@code str}. * * @param str * string to search in * @param sub * string to search for */ public static int countOccurrencesOf(String str, String sub) { if (!hasLength(str) || !hasLength(sub)) { return 0; } int count = 0; int pos = 0; int idx; while ((idx = str.indexOf(sub, pos)) != -1) { ++count; pos = idx + sub.length(); } return count; } /** * Replace all occurrences of a substring within a string with another * string. * * @param inString * {@code String} to examine * @param oldPattern * {@code String} to replace * @param newPattern * {@code String} to insert * @return a {@code String} with the replacements */ public static String replace(String inString, String oldPattern, String newPattern) { if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { return inString; } int index = inString.indexOf(oldPattern); if (index == -1) { // no occurrence -> can return input as-is return inString; } int capacity = inString.length(); if (newPattern.length() > oldPattern.length()) { capacity += 16; } StringBuilder sb = new StringBuilder(capacity); int pos = 0; // our position in the old string int patLen = oldPattern.length(); while (index >= 0) { sb.append(inString.substring(pos, index)); sb.append(newPattern); pos = index + patLen; index = inString.indexOf(oldPattern, pos); } // append any characters to the right of a match sb.append(inString.substring(pos)); return sb.toString(); } /** * Delete all occurrences of the given substring. * * @param inString * the original {@code String} * @param pattern * the pattern to delete all occurrences of * @return the resulting {@code String} */ public static String delete(String inString, String pattern) { return replace(inString, pattern, ""); } /** * Delete any character in a given {@code String}. * * @param inString * the original {@code String} * @param charsToDelete * a set of characters to delete. E.g. "az\n" will delete 'a's, * 'z's and new lines. * @return the resulting {@code String} */ public static String deleteAny(String inString, String charsToDelete) { if (!hasLength(inString) || !hasLength(charsToDelete)) { return inString; } StringBuilder sb = new StringBuilder(inString.length()); for (int i = 0; i < inString.length(); i++) { char c = inString.charAt(i); if (charsToDelete.indexOf(c) == -1) { sb.append(c); } } return sb.toString(); } /** * Copy the given {@code Collection} into a {@code String} array. *

    * The {@code Collection} must contain {@code String} elements only. * * @param collection * the {@code Collection} to copy * @return the {@code String} array */ public static String[] toStringArray(Collection collection) { if (collection == null) { return null; } return collection.toArray(new String[collection.size()]); } /** * Check that the given {@code CharSequence} is neither {@code null} nor of * length 0. *

    * Note: this method returns {@code true} for a {@code CharSequence} that * purely consists of whitespace. *

    * *

         * StringUtils.hasLength(null) = false
         * StringUtils.hasLength("") = false
         * StringUtils.hasLength(" ") = true
         * StringUtils.hasLength("Hello") = true
         * 
    * * @param str * the {@code CharSequence} to check (may be {@code null}) * @return {@code true} if the {@code CharSequence} is not {@code null} and * has length * @see #hasText(String) */ public static boolean hasLength(CharSequence str) { return (str != null && str.length() > 0); } /** * Check that the given {@code String} is neither {@code null} nor of length * 0. *

    * Note: this method returns {@code true} for a {@code String} that purely * consists of whitespace. * * @param str * the {@code String} to check (may be {@code null}) * @return {@code true} if the {@code String} is not {@code null} and has * length * @see #hasLength(CharSequence) * @see #hasText(String) */ public static boolean hasLength(String str) { return (str != null && !str.isEmpty()); } /** * Normalize the path by suppressing sequences like "path/.." and inner * simple dots. *

    * The result is convenient for path comparison. For other uses, notice that * Windows separators ("\") are replaced by simple slashes. * * @param path * the original path * @return the normalized path */ public static String cleanPath(String path) { if (path == null) { return null; } String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); // Strip prefix from path to analyze, to not treat it as part of the // first path element. This is necessary to correctly parse paths like // "file:core/../core/io/Resource.class", where the ".." should just // strip the first "core" directory while keeping the "file:" prefix. int prefixIndex = pathToUse.indexOf(':'); String prefix = ""; if (prefixIndex != -1) { prefix = pathToUse.substring(0, prefixIndex + 1); if (prefix.contains("/")) { prefix = ""; } else { pathToUse = pathToUse.substring(prefixIndex + 1); } } if (pathToUse.startsWith(FOLDER_SEPARATOR)) { prefix = prefix + FOLDER_SEPARATOR; pathToUse = pathToUse.substring(1); } String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); List pathElements = new LinkedList(); int tops = 0; for (int i = pathArray.length - 1; i >= 0; i--) { String element = pathArray[i]; if (CURRENT_PATH.equals(element)) { // Points to current directory - drop it. } else if (TOP_PATH.equals(element)) { // Registering top path found. tops++; } else { if (tops > 0) { // Merging path element with element corresponding to top // path. tops--; } else { // Normal path element found. pathElements.add(0, element); } } } // Remaining top paths need to be retained. for (int i = 0; i < tops; i++) { pathElements.add(0, TOP_PATH); } return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); } /** * Apply the given relative path to the given Java resource path, assuming * standard Java folder separation (i.e. "/" separators). * * @param path * the path to start from (usually a full file path) * @param relativePath * the relative path to apply (relative to the full file path * above) * @return the full file path that results from applying the relative path */ public static String applyRelativePath(String path, String relativePath) { int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); if (separatorIndex != -1) { String newPath = path.substring(0, separatorIndex); if (!relativePath.startsWith(FOLDER_SEPARATOR)) { newPath += FOLDER_SEPARATOR; } return newPath + relativePath; } else { return relativePath; } } /** * Decode the given encoded URI component value. Based on the following * rules: *

      *
    • Alphanumeric characters {@code "a"} through {@code "z"}, {@code "A"} * through {@code "Z"}, and {@code "0"} through {@code "9"} stay the * same.
    • *
    • Special characters {@code "-"}, {@code "_"}, {@code "."}, and * {@code "*"} stay the same.
    • *
    • A sequence "{@code %xy}" is interpreted as a hexadecimal * representation of the character.
    • *
    * * @param source * the encoded String * @param charset * the character set * @return the decoded value * @throws IllegalArgumentException * when the given source contains invalid encoded sequences * @since 5.0 * @see java.net.URLDecoder#decode(String, String) */ public static String uriDecode(String source, Charset charset) { int length = source.length(); if (length == 0) { return source; } Assert2.notNull(charset, "Charset must not be null"); ByteArrayOutputStream bos = new ByteArrayOutputStream(length); boolean changed = false; for (int i = 0; i < length; i++) { int ch = source.charAt(i); if (ch == '%') { if (i + 2 < length) { char hex1 = source.charAt(i + 1); char hex2 = source.charAt(i + 2); int u = Character.digit(hex1, 16); int l = Character.digit(hex2, 16); if (u == -1 || l == -1) { throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\""); } bos.write((char) ((u << 4) + l)); i += 2; changed = true; } else { throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\""); } } else { bos.write(ch); } } return (changed ? new String(bos.toByteArray(), charset) : source); } /** * Searches the given pattern in the given src string and applies the txr to * the matches * * @param src * The string to be converted * @param pattern * the pattern for which the transformers to be applied. * @param process * The transformers for the mathed patterns. * @return The result after applying the transformation. * @see https://www.regular-expressions.info/refreplacecase.html */ public static String replaceGroups( final @NotBlank String src, final @NotBlank String pattern, final @NotNull Function process) { hasTextOf(src, "src"); hasTextOf(pattern, "pattern"); final Matcher matcher = Pattern.compile(pattern).matcher(src); final StringBuilder newStr = new StringBuilder(); int index = 0; while (matcher.find()) { // sb.append(src.substring(last, m.start())); for (int start = index++, i = start; i < start + matcher.groupCount(); i++) { newStr.append(process.apply(new GroupSubString(i, matcher.group(i + 1), newStr))); } } // sb.append(src.substring(last)); return newStr.toString(); } @Getter @ToString @AllArgsConstructor public static class GroupSubString { private int index; private String groupStr; private StringBuilder newStr; } /** * Calculates the value of the corresponding expression based on a numeric * expression * * @author His father is james wong * @version v1.0 2014-07-29 * @sine */ @Getter @SuperBuilder @ToString @NoArgsConstructor public static class SimpleMathExpressions { private static final String CHAE_L = "("; private static final String CHAE_R = ")"; private static final String ADD = "+"; private static final String MIN = "-"; private static final String MUL = "*"; private static final String DIV = "/"; private static final String MOD = "%"; // test private static final String BT = ">"; private static final String LT = "<"; private static final String EQ = "="; private static final String NOT_EQ = "N"; // != private static final String AND = "&"; private static final String OR = "|"; private static final String NOT = "!"; private static final String BT_EQ = "B"; // >= private static final String LT_EQ = "X"; // <= public static Object calculate(@NotBlank String expStr) throws Exception { hasTextOf(expStr, expStr); // init and check expression str expStr = init(expStr); // get calculate item ItemCalculate item = new ItemCalculate(null, expStr); item.genCalculateItem(); // calculate item.calculate(); return item.getResult(); } public static boolean test(String expStr) throws Exception { Object obj = calculate(expStr); if (obj instanceof Boolean) { return (Boolean) obj; } else { throw new Exception("test calculate error."); } } public static class ItemCalculate { private String sign; private String expStr; private List sonItemList = null; private Object result = null; public ItemCalculate(String sign, String expStr) { this.sign = sign; this.expStr = expStr; } private boolean isBoolean() { if (result != null) { if (result instanceof Boolean) { return true; } else { return false; } } if ("TRUE".equals(expStr) || "FALSE".equals(expStr)) { return true; } return false; } private boolean isInteger() { if (result != null) { if (result instanceof Integer) { return true; } else { return false; } } if (!isBoolean() && expStr.indexOf(".") < 0) return true; return false; } private boolean isDouble() { if (result != null) { if (result instanceof Double) { return true; } else { return false; } } if (expStr.indexOf(".") > 0) return true; return false; } public void genCalculateItem() throws Exception { int index = 0; String lastSign = null; for (int i = 0; i < expStr.length(); i++) { String one = expStr.substring(i, i + 1); if (isSign(one) || isTestSign(one)) {// before if (i == 0) { lastSign = one; index = i + 1; } else { String numStr = expStr.substring(index, i); this.addItem(lastSign, numStr); lastSign = one; index = i + 1; } } else if (isLkuohao(one)) {// after int oKuohaoIndex = getOtherKuohaoIndex(expStr, i); if (oKuohaoIndex < 0) throw new Exception("expression str error1, '(',')' not matching."); String sonExpStr = expStr.substring(index + 1, oKuohaoIndex); ItemCalculate item = this.addItem(lastSign, sonExpStr); item.genCalculateItem(); if (oKuohaoIndex >= expStr.length() - 1) return; lastSign = expStr.substring(oKuohaoIndex + 1, oKuohaoIndex + 2); if (!isSign(lastSign) && !isTestSign(lastSign)) { throw new Exception("expression str error, not a sign char (" + lastSign + ")."); } index = oKuohaoIndex + 2; i = index - 1; } else if (i == expStr.length() - 1) { String numStr = expStr.substring(index, i + 1); this.addItem(lastSign, numStr); } } } public void calculate() throws Exception { if (sonItemList == null) { if (isBoolean()) { Boolean t = getBoolean(getExpStr()); setResult(t); } else if (isDouble()) { setResult(getDouble(getExpStr())); } else if (isInteger()) { setResult(getInteger(getExpStr())); } return; } for (int i = 0; i < sonItemList.size(); i++) { ItemCalculate sonItem = sonItemList.get(i); sonItem.calculate(); // System.out.println("temp result:"+sonItem.getResult()+", // sign:"+sonItem.getSign()+", // expStr:"+sonItem.getExpStr()); } ItemCalculate lastItem = null; /** * *,/,% */ lastItem = null; for (int i = 0; i < sonItemList.size(); i++) { if (sonItemList.size() < 2) break; ItemCalculate sonItem = sonItemList.get(i); String sign = sonItem.getSign(); if (isHightLeavl(sign) && lastItem != null) { Integer lRsti = null; Double lRstd = null; Integer sRsti = null; Double sRstd = null; if (lastItem.isInteger()) lRsti = (Integer) lastItem.getResult(); else if (lastItem.isDouble()) lRstd = (Double) lastItem.getResult(); else { throw new Exception("errorA1."); } if (sonItem.isInteger()) sRsti = (Integer) sonItem.getResult(); else if (sonItem.isDouble()) sRstd = (Double) sonItem.getResult(); else { throw new Exception("errorA2."); } if (MUL.equals(sign)) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti * sRsti); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti * sRstd); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd * sRsti); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd * sRstd); } } else if (DIV.equals(sign)) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti / sRsti); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti / sRstd); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd / sRsti); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd / sRstd); } } else if (MOD.equals(sign)) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti % sRsti); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti % sRstd); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd % sRsti); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd % sRstd); } } sonItemList.remove(i); i = -1; lastItem = null; continue; } lastItem = sonItem; } /** * +,- */ lastItem = null; for (int i = 0; i < sonItemList.size(); i++) { if (sonItemList.size() < 2) break; ItemCalculate sonItem = sonItemList.get(i); if (i == 0) { lastItem = sonItem; continue; } String sign = sonItem.getSign(); if (isSign(sign) && !isHightLeavl(sign) && lastItem != null) { Integer lRsti = null; Double lRstd = null; Integer sRsti = null; Double sRstd = null; if (lastItem.isInteger()) lRsti = (Integer) lastItem.getResult(); else if (lastItem.isDouble()) lRstd = (Double) lastItem.getResult(); else { throw new Exception("errorB1."); } if (sonItem.isInteger()) sRsti = (Integer) sonItem.getResult(); else if (sonItem.isDouble()) sRstd = (Double) sonItem.getResult(); else { throw new Exception("errorB2."); } if (MIN.equals(lastItem.getSign())) { if (lRsti != null) lRsti = -lRsti; else if (lRstd != null) lRstd = -lRstd; lastItem.setSign(ADD); } if (ADD.equals(sign)) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti + sRsti); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti + sRstd); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd + sRsti); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd + sRstd); } } else if (MIN.equals(sign)) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti - sRsti); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti - sRstd); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd - sRsti); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd - sRstd); } } sonItemList.remove(i); i = -1; lastItem = null; } } /* * <,>,! .... !true&false)=false (5>2) && ((4+3-6) < 44) */ lastItem = null; for (int i = 0; i < sonItemList.size(); i++) { if (sonItemList.size() < 2) break; ItemCalculate sonItem = sonItemList.get(i); String sign = sonItem.getSign(); if (NOT.equals(sonItem.getSign())) { if (!sonItem.isBoolean()) { throw new Exception("Error,'!' sign must map a boolean value."); } Boolean t = (Boolean) sonItem.getResult(); sonItem.setResult(!t); sonItem.setSign(null); } if (isTestHightLeavl(sign) && lastItem != null) { Integer lRsti = null; Double lRstd = null; Boolean lRstb = null; Integer sRsti = null; Double sRstd = null; Boolean sRstb = null; if (lastItem.isInteger()) lRsti = (Integer) lastItem.getResult(); else if (lastItem.isDouble()) lRstd = (Double) lastItem.getResult(); else if (lastItem.isBoolean()) { lRstb = (Boolean) lastItem.getResult(); } if (sonItem.isInteger()) sRsti = (Integer) sonItem.getResult(); else if (sonItem.isDouble()) sRstd = (Double) sonItem.getResult(); else if (sonItem.isBoolean()) { sRstb = (Boolean) sonItem.getResult(); } if (BT.equals(sign)) { if (!lastItem.isBoolean() && !sonItem.isBoolean()) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti.intValue() > sRsti.intValue()); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti.intValue() > sRstd.doubleValue()); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd.doubleValue() > sRsti.intValue()); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd.doubleValue() > sRstd.doubleValue()); } } else { throw new Exception("Error exp str, can not calculate boolean with number1."); } } else if (LT.equals(sign)) { if (!lastItem.isBoolean() && !sonItem.isBoolean()) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti.intValue() < sRsti.intValue()); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti.intValue() < sRstd.doubleValue()); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd.doubleValue() < sRsti.intValue()); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd.doubleValue() < sRstd.doubleValue()); } } else { throw new Exception("Error exp str, can not calculate boolean with number2."); } } else if (BT_EQ.equals(sign)) { if (!lastItem.isBoolean() && !sonItem.isBoolean()) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti.intValue() >= sRsti.intValue()); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti.intValue() >= sRstd.doubleValue()); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd.doubleValue() >= sRsti.intValue()); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd.doubleValue() >= sRstd.doubleValue()); } } else { throw new Exception("Error exp str, can not calculate boolean with number3."); } } else if (LT_EQ.equals(sign)) { if (!lastItem.isBoolean() && !sonItem.isBoolean()) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti.intValue() <= sRsti.intValue()); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti.intValue() <= sRstd.doubleValue()); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd.doubleValue() <= sRsti.intValue()); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd.doubleValue() <= sRstd.doubleValue()); } } else { throw new Exception("Error exp str, can not calculate boolean with number4."); } } else if (EQ.equals(sign)) { if (!lastItem.isBoolean() && !sonItem.isBoolean()) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti.intValue() == sRsti.intValue()); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti.intValue() == sRstd.doubleValue()); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd.doubleValue() == sRsti.intValue()); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd.doubleValue() == sRstd.doubleValue()); } } else if (lastItem.isBoolean() && sonItem.isBoolean()) { // System.out.println("**********"+lRstb.booleanValue()+"/"+sRstb.booleanValue()); lastItem.setResult(lRstb.booleanValue() == sRstb.booleanValue()); } else { throw new Exception("Error exp str, can not calculate boolean with number5."); } } else if (NOT_EQ.equals(sign)) { if (!lastItem.isBoolean() && !sonItem.isBoolean()) { if (lRsti != null && sRsti != null) { lastItem.setResult(lRsti.intValue() != sRsti.intValue()); } else if (lRsti != null && sRstd != null) { lastItem.setResult(lRsti.intValue() != sRstd.doubleValue()); } else if (lRstd != null && sRsti != null) { lastItem.setResult(lRstd.doubleValue() != sRsti.intValue()); } else if (lRstd != null && sRstd != null) { lastItem.setResult(lRstd.doubleValue() != sRstd.doubleValue()); } } else if (lastItem.isBoolean() && sonItem.isBoolean()) { lastItem.setResult(lRstb.booleanValue() != sRstb.booleanValue()); } else { throw new Exception("Error exp str, can not calculate boolean with number6."); } } // -------- sonItemList.remove(i); i = -1; lastItem = null; continue; } lastItem = sonItem; } /* * &&,|| */ lastItem = null; for (int i = 0; i < sonItemList.size(); i++) { if (sonItemList.size() < 2) break; ItemCalculate sonItem = sonItemList.get(i); String sign = sonItem.getSign(); if (isTestSign(sign) && !isTestHightLeavl(sign) && lastItem != null) { Boolean lRstb = null; Boolean sRstb = null; if (lastItem.isBoolean()) { lRstb = (Boolean) lastItem.getResult(); } if (sonItem.isBoolean()) { sRstb = (Boolean) sonItem.getResult(); } if (AND.equals(sign)) { if (lastItem.isBoolean() && sonItem.isBoolean()) { // System.out.println("**********"+lRstb.booleanValue()+"/"+sRstb.booleanValue()); lastItem.setResult(lRstb.booleanValue() == true && sRstb.booleanValue() == true); } else { throw new Exception( "Error exp str, can not calculate (boolean with number) or (number with number)7."); } } else if (OR.equals(sign)) { if (lastItem.isBoolean() && sonItem.isBoolean()) { lastItem.setResult(lRstb.booleanValue() == true || sRstb.booleanValue() == true); } else { throw new Exception( "Error exp str, can not calculate (boolean with number) or (number with number)8."); } } // -------- sonItemList.remove(i); i = -1; lastItem = null; continue; } lastItem = sonItem; } // ////////////////////////////////////////////////// ItemCalculate item = sonItemList.get(0); if (MIN.equals(item.getSign())) { if (item.isInteger()) { Integer res = getInteger(item.getResult()); setResult(-res); } else if (item.isDouble()) { Double res = getDouble(item.getResult()); setResult(-res); } else { throw new Exception("error1."); } } else if (NOT.equals(item.getSign())) { if (item.getResult() instanceof Boolean) { Boolean bool = (Boolean) item.getResult(); setResult(!bool); // System.out.println("============="+item.getResult()); } else { throw new Exception("error2."); } } else if (ADD.equals(item.getSign()) || item.getSign() == null) { setResult(item.getResult()); } else { throw new Exception("error3."); } } @SuppressWarnings("unused") public ItemCalculate addItem(String sign, String expStr) { // System.out.println("item: sign='"+sign+"', // expStr='"+expStr+"'"); ItemCalculate item = new ItemCalculate(sign, expStr); if (item == null) return null; if (sonItemList == null) sonItemList = new ArrayList(); sonItemList.add(item); return item; } public String getExpStr() { return expStr; } public void setExpStr(String expStr) { this.expStr = expStr; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } public List getSonItemList() { return sonItemList; } public Object getResult() { return result; } public void setResult(Object result) { this.result = result; } } private static String replaceAll(String strVal, String o, String n) { if (strVal == null || o == null || n == null || "".equals(o)) return strVal; int oLen = o.length(); StringBuffer buf = new StringBuffer(); int index = 0; int ind = strVal.indexOf(o); while (ind > -1) { buf.append(strVal.substring(index, ind)); buf.append(n); index = ind + oLen; ind = strVal.indexOf(o, index); } buf.append(strVal.substring(index, strVal.length())); return buf.toString(); } /** * 7>4&!(5>1)=false --> 7>4&(!(5>1))=false 7>4&!true=false --> * 7>4&(!true)=false 7>-4&-(4+5)>1 --> 7>(-4)&(-5)>1 * * @param expStr * @return */ private static String updateExpStr(String expStr) { String lastSign = null; StringBuffer buf = new StringBuffer(); int index = 0; for (int i = 0; i < expStr.length(); i++) { String one = expStr.substring(i, i + 1); if (isSign(one) || isTestSign(one)) { if (lastSign == null) { lastSign = one; continue; } String tItem[] = getItemExpStr(expStr, i); tItem[0] = updateExpStr(tItem[0]); buf.append(expStr.substring(index, i)); buf.append("(" + tItem[0] + ")"); index = Integer.parseInt(tItem[1]); } else { lastSign = null; } } buf.append(expStr.substring(index)); return buf.toString(); } private static String[] getItemExpStr(String expStr, int signInd) { int endInd = expStr.length(); for (int i = signInd + 1; i < expStr.length(); i++) { String one = expStr.substring(i, i + 1); if (isLkuohao(one) && i == signInd + 1) { int rInd = getOtherKuohaoIndex(expStr, i); return new String[] { expStr.substring(signInd, rInd + 1), (rInd + 1) + "" }; } if (isSign(one) || isTestSign(one) || isRkuohao(one) || isLkuohao(one)) { endInd = i; break; } } return new String[] { expStr.substring(signInd, endInd), endInd + "" }; } /** * init and check expression string * * @param expStr * @return * @throws Exception */ private static String init(String expStr) throws Exception { if (expStr == null || expStr.trim().equals("")) throw new Exception("expression str error, is empty."); // to upper case expStr = expStr.toUpperCase(); expStr = replaceAll(expStr, "!=", NOT_EQ); expStr = replaceAll(expStr, "<>", NOT_EQ); expStr = replaceAll(expStr, ">=", BT_EQ); expStr = replaceAll(expStr, "<=", LT_EQ); expStr = replaceAll(expStr, "&&", AND); expStr = replaceAll(expStr, "==", EQ); expStr = replaceAll(expStr, "||", OR); // remove " " string expStr = expStr.replaceAll(" ", ""); // System.out.println("mid, expStr : "+expStr); expStr = updateExpStr(expStr); // System.out.println("end, expStr : "+expStr); // check "(",")" int lnum = 0; int rnum = 0; boolean lastIsSign = false; String lastSign = null; for (int i = 0; i < expStr.length(); i++) { String one = expStr.substring(i, i + 1); if (CHAE_L.equals(one)) { lnum++; } if (CHAE_R.equals(one)) { rnum++; } if (isSign(one) || isTestSign(one)) { if (lastIsSign) { throw new Exception("expression str error, sign together (" + lastSign + one + ")."); } lastIsSign = true; lastSign = one; } else { lastIsSign = false; lastSign = ""; } } if (rnum != lnum) { throw new Exception("expression str error, '(',')' not matching."); } return expStr; } private static int getOtherKuohaoIndex(String expStr, int lkuoHaoIndex) { int rnum = 0; int lnum = 0; for (int i = lkuoHaoIndex + 1; i < expStr.length(); i++) { String one = expStr.substring(i, i + 1); if (isLkuohao(one)) { lnum++; } else if (isRkuohao(one)) { if (lnum == rnum) return i; rnum++; } } return -1; } private static Double getDouble(Object val) throws Exception { if (val == null) throw new Exception("expression str error, Double null."); return new Double(val.toString()); } private static Boolean getBoolean(Object val) throws Exception { if (val == null) throw new Exception("expression str error, Boolean null."); return new Boolean(val.toString()); } private static Integer getInteger(Object val) throws Exception { if (val == null) throw new Exception("expression str error, Double null."); return new Integer(val.toString()); } private static boolean isHightLeavl(String val) { if (MUL.equals(val) || DIV.equals(val) || MOD.equals(val)) { return true; } return false; } private static boolean isSign(String val) { if (ADD.equals(val) || MIN.equals(val) || MUL.equals(val) || DIV.equals(val) || MOD.equals(val)) { return true; } return false; } private static boolean isTestHightLeavl(String val) { if (BT.equals(val) || LT.equals(val) || EQ.equals(val) || NOT_EQ.equals(val) || NOT.equals(val) || BT_EQ.equals(val) || LT_EQ.equals(val)) { return true; } return false; } private static boolean isTestSign(String val) { if (BT.equals(val) || LT.equals(val) || EQ.equals(val) || NOT_EQ.equals(val) || AND.equals(val) || OR.equals(val) || NOT.equals(val) || BT_EQ.equals(val) || LT_EQ.equals(val)) { return true; } return false; } private static boolean isLkuohao(String val) { if (CHAE_L.equals(val)) { return true; } return false; } private static boolean isRkuohao(String val) { if (CHAE_R.equals(val)) { return true; } return false; } } }




    © 2015 - 2024 Weber Informatics LLC | Privacy Policy