|
@@ -15,6 +15,7 @@
|
|
|
*/
|
|
|
package com.baomidou.mybatisplus.toolkit;
|
|
|
|
|
|
+import java.sql.Blob;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
@@ -23,6 +24,8 @@ import java.util.List;
|
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
|
|
|
+
|
|
|
/**
|
|
|
* <p>
|
|
|
* String 工具类
|
|
@@ -33,769 +36,795 @@ import java.util.regex.Pattern;
|
|
|
*/
|
|
|
public class StringUtils {
|
|
|
|
|
|
- /**
|
|
|
- * 空字符
|
|
|
- */
|
|
|
- public static final String EMPTY = "";
|
|
|
- /**
|
|
|
- * 字符串 is
|
|
|
- */
|
|
|
- public static final String IS = "is";
|
|
|
-
|
|
|
- /**
|
|
|
- * 下划线字符
|
|
|
- */
|
|
|
- public static final char UNDERLINE = '_';
|
|
|
-
|
|
|
- /**
|
|
|
- * 占位符
|
|
|
- */
|
|
|
- public static final String PLACE_HOLDER = "{%s}";
|
|
|
-
|
|
|
- private static boolean separatorBeforeDigit = false;
|
|
|
- private static boolean separatorAfterDigit = true;
|
|
|
-
|
|
|
-
|
|
|
- private StringUtils() {
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 判断字符串是否为空
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param cs 需要判断字符串
|
|
|
- * @return 判断结果
|
|
|
- */
|
|
|
- public static boolean isEmpty(final CharSequence cs) {
|
|
|
- int strLen;
|
|
|
- if (cs == null || (strLen = cs.length()) == 0) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- for (int i = 0; i < strLen; i++) {
|
|
|
- if (!Character.isWhitespace(cs.charAt(i))) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 判断字符串是否不为空
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param cs 需要判断字符串
|
|
|
- * @return 判断结果
|
|
|
- */
|
|
|
- public static boolean isNotEmpty(final CharSequence cs) {
|
|
|
- return !isEmpty(cs);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 字符串驼峰转下划线格式
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param param 需要转换的字符串
|
|
|
- * @return 转换好的字符串
|
|
|
- */
|
|
|
- public static String camelToUnderline(String param) {
|
|
|
- if (isEmpty(param)) {
|
|
|
- return EMPTY;
|
|
|
- }
|
|
|
- int len = param.length();
|
|
|
- StringBuilder sb = new StringBuilder(len);
|
|
|
- for (int i = 0; i < len; i++) {
|
|
|
- char c = param.charAt(i);
|
|
|
- if (Character.isUpperCase(c) && i > 0) {
|
|
|
- sb.append(UNDERLINE);
|
|
|
- }
|
|
|
- sb.append(Character.toLowerCase(c));
|
|
|
- }
|
|
|
- return sb.toString();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 字符串下划线转驼峰格式
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param param 需要转换的字符串
|
|
|
- * @return 转换好的字符串
|
|
|
- */
|
|
|
- public static String underlineToCamel(String param) {
|
|
|
- if (isEmpty(param)) {
|
|
|
- return EMPTY;
|
|
|
- }
|
|
|
- String temp = param.toLowerCase();
|
|
|
- int len = temp.length();
|
|
|
- StringBuilder sb = new StringBuilder(len);
|
|
|
- for (int i = 0; i < len; i++) {
|
|
|
- char c = temp.charAt(i);
|
|
|
- if (c == UNDERLINE) {
|
|
|
- if (++i < len) {
|
|
|
- sb.append(Character.toUpperCase(temp.charAt(i)));
|
|
|
- }
|
|
|
- } else {
|
|
|
- sb.append(c);
|
|
|
- }
|
|
|
- }
|
|
|
- return sb.toString();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 首字母转换小写
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param param 需要转换的字符串
|
|
|
- * @return 转换好的字符串
|
|
|
- */
|
|
|
- public static String firstToLowerCase(String param) {
|
|
|
- if (isEmpty(param)) {
|
|
|
- return EMPTY;
|
|
|
- }
|
|
|
- StringBuilder sb = new StringBuilder(param.length());
|
|
|
- sb.append(param.substring(0, 1).toLowerCase());
|
|
|
- sb.append(param.substring(1));
|
|
|
- return sb.toString();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 判断字符串是否为纯大写字母
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param str 要匹配的字符串
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static boolean isUpperCase(String str) {
|
|
|
- return match("^[A-Z]+$", str);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 正则表达式匹配
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param regex 正则表达式字符串
|
|
|
- * @param str 要匹配的字符串
|
|
|
- * @return 如果str 符合 regex的正则表达式格式,返回true, 否则返回 false;
|
|
|
- */
|
|
|
- public static boolean match(String regex, String str) {
|
|
|
- Pattern pattern = Pattern.compile(regex);
|
|
|
- Matcher matcher = pattern.matcher(str);
|
|
|
- return matcher.matches();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * SQL 参数填充
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param content 填充内容
|
|
|
- * @param args 填充参数
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String sqlArgsFill(String content, Object... args) {
|
|
|
- if (StringUtils.isEmpty(content)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (args != null) {
|
|
|
- int length = args.length;
|
|
|
- if (length >= 1) {
|
|
|
- for (int i = 0; i < length; i++) {
|
|
|
- content = content.replace(String.format(PLACE_HOLDER, i), sqlParam(args[i]));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return content;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 获取SQL PARAMS字符串
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param obj
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String sqlParam(Object obj) {
|
|
|
- String repStr;
|
|
|
- if (obj instanceof Collection) {
|
|
|
- repStr = StringUtils.quotaMarkList((Collection<?>) obj);
|
|
|
- } else {
|
|
|
- repStr = StringUtils.quotaMark(obj);
|
|
|
- }
|
|
|
- return repStr;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 使用单引号包含字符串
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param obj 原字符串
|
|
|
- * @return 单引号包含的原字符串
|
|
|
- */
|
|
|
- public static String quotaMark(Object obj) {
|
|
|
- String srcStr = String.valueOf(obj);
|
|
|
- if (obj instanceof CharSequence) {
|
|
|
- // fix #79
|
|
|
- return StringEscape.escapeString(srcStr);
|
|
|
- }
|
|
|
- return srcStr;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 使用单引号包含字符串
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param coll 集合
|
|
|
- * @return 单引号包含的原字符串的集合形式
|
|
|
- */
|
|
|
- public static String quotaMarkList(Collection<?> coll) {
|
|
|
- StringBuilder sqlBuild = new StringBuilder();
|
|
|
- sqlBuild.append("(");
|
|
|
- int size = coll.size();
|
|
|
- int i = 0;
|
|
|
- Iterator<?> iterator = coll.iterator();
|
|
|
- while (iterator.hasNext()) {
|
|
|
- String tempVal = StringUtils.quotaMark(iterator.next());
|
|
|
- sqlBuild.append(tempVal);
|
|
|
- if (i + 1 < size) {
|
|
|
- sqlBuild.append(",");
|
|
|
- }
|
|
|
- i++;
|
|
|
- }
|
|
|
- sqlBuild.append(")");
|
|
|
- return sqlBuild.toString();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 拼接字符串第二个字符串第一个字母大写
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param concatStr
|
|
|
- * @param str
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String concatCapitalize(String concatStr, final String str) {
|
|
|
- if (isEmpty(concatStr)) {
|
|
|
- concatStr = EMPTY;
|
|
|
- }
|
|
|
- int strLen;
|
|
|
- if (str == null || (strLen = str.length()) == 0) {
|
|
|
- return str;
|
|
|
- }
|
|
|
-
|
|
|
- final char firstChar = str.charAt(0);
|
|
|
- if (Character.isTitleCase(firstChar)) {
|
|
|
- // already capitalized
|
|
|
- return str;
|
|
|
- }
|
|
|
-
|
|
|
- StringBuilder sb = new StringBuilder(strLen);
|
|
|
- sb.append(concatStr);
|
|
|
- sb.append(Character.toTitleCase(firstChar));
|
|
|
- sb.append(str.substring(1));
|
|
|
- return sb.toString();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 字符串第一个字母大写
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param str
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String capitalize(final String str) {
|
|
|
- return concatCapitalize(null, str);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 判断对象是否为空
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param object
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static boolean checkValNotNull(Object object) {
|
|
|
- if (object instanceof CharSequence) {
|
|
|
- return isNotEmpty((CharSequence) object);
|
|
|
- }
|
|
|
- return object != null;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 判断对象是否为空
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param object
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static boolean checkValNull(Object object) {
|
|
|
- return !checkValNotNull(object);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 包含大写字母
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param word 待判断字符串
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static boolean containsUpperCase(String word) {
|
|
|
- for (int i = 0; i < word.length(); i++) {
|
|
|
- char c = word.charAt(i);
|
|
|
- if (Character.isUpperCase(c)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 是否为大写命名
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param word 待判断字符串
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static boolean isCapitalMode(String word) {
|
|
|
- return null != word && word.matches("^[0-9A-Z/_]+$");
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 是否为驼峰下划线混合命名
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param word 待判断字符串
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static boolean isMixedMode(String word) {
|
|
|
- return Pattern.compile(".*[A-Z]+.*").matcher(word).matches() && Pattern.compile(".*[/_]+.*").matcher(word).matches();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * Check if a String ends with a specified suffix.
|
|
|
- * </p>
|
|
|
- * <p>
|
|
|
- * <p>
|
|
|
- * <code>null</code>s are handled without exceptions. Two <code>null</code>
|
|
|
- * references are considered to be equal. The comparison is case sensitive.
|
|
|
- * </p>
|
|
|
- * <p>
|
|
|
- * <pre>
|
|
|
- * StringUtils.endsWith(null, null) = true
|
|
|
- * StringUtils.endsWith(null, "abcdef") = false
|
|
|
- * StringUtils.endsWith("def", null) = false
|
|
|
- * StringUtils.endsWith("def", "abcdef") = true
|
|
|
- * StringUtils.endsWith("def", "ABCDEF") = false
|
|
|
- * </pre>
|
|
|
- *
|
|
|
- * @param str the String to check, may be null
|
|
|
- * @param suffix the suffix to find, may be null
|
|
|
- * @return <code>true</code> if the String ends with the suffix, case
|
|
|
- * sensitive, or both <code>null</code>
|
|
|
- * @see java.lang.String#endsWith(String)
|
|
|
- * @since 2.4
|
|
|
- */
|
|
|
- public static boolean endsWith(String str, String suffix) {
|
|
|
- return endsWith(str, suffix, false);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * Case insensitive check if a String ends with a specified suffix.
|
|
|
- * </p>
|
|
|
- * <p>
|
|
|
- * <p>
|
|
|
- * <code>null</code>s are handled without exceptions. Two <code>null</code>
|
|
|
- * references are considered to be equal. The comparison is case
|
|
|
- * insensitive.
|
|
|
- * </p>
|
|
|
- * <p>
|
|
|
- * <pre>
|
|
|
- * StringUtils.endsWithIgnoreCase(null, null) = true
|
|
|
- * StringUtils.endsWithIgnoreCase(null, "abcdef") = false
|
|
|
- * StringUtils.endsWithIgnoreCase("def", null) = false
|
|
|
- * StringUtils.endsWithIgnoreCase("def", "abcdef") = true
|
|
|
- * StringUtils.endsWithIgnoreCase("def", "ABCDEF") = false
|
|
|
- * </pre>
|
|
|
- *
|
|
|
- * @param str the String to check, may be null
|
|
|
- * @param suffix the suffix to find, may be null
|
|
|
- * @return <code>true</code> if the String ends with the suffix, case
|
|
|
- * insensitive, or both <code>null</code>
|
|
|
- * @see java.lang.String#endsWith(String)
|
|
|
- * @since 2.4
|
|
|
- */
|
|
|
- public static boolean endsWithIgnoreCase(String str, String suffix) {
|
|
|
- return endsWith(str, suffix, true);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * Check if a String ends with a specified suffix (optionally case
|
|
|
- * insensitive).
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param str the String to check, may be null
|
|
|
- * @param suffix the suffix to find, may be null
|
|
|
- * @param ignoreCase inidicates whether the compare should ignore case (case
|
|
|
- * insensitive) or not.
|
|
|
- * @return <code>true</code> if the String starts with the prefix or both
|
|
|
- * <code>null</code>
|
|
|
- * @see java.lang.String#endsWith(String)
|
|
|
- */
|
|
|
- private static boolean endsWith(String str, String suffix, boolean ignoreCase) {
|
|
|
- if (str == null || suffix == null) {
|
|
|
- return (str == null && suffix == null);
|
|
|
- }
|
|
|
- if (suffix.length() > str.length()) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- int strOffset = str.length() - suffix.length();
|
|
|
- return str.regionMatches(ignoreCase, strOffset, suffix, 0, suffix.length());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * Splits the provided text into an array, separators specified. This is an
|
|
|
- * alternative to using StringTokenizer.
|
|
|
- * </p>
|
|
|
- * <p>
|
|
|
- * <p>
|
|
|
- * The separator is not included in the returned String array. Adjacent
|
|
|
- * separators are treated as one separator. For more control over the split
|
|
|
- * use the StrTokenizer class.
|
|
|
- * </p>
|
|
|
- * <p>
|
|
|
- * <p>
|
|
|
- * A {@code null} input String returns {@code null}. A {@code null}
|
|
|
- * separatorChars splits on whitespace.
|
|
|
- * </p>
|
|
|
- * <p>
|
|
|
- * <pre>
|
|
|
- * StringUtils.split(null, *) = null
|
|
|
- * StringUtils.split("", *) = []
|
|
|
- * StringUtils.split("abc def", null) = ["abc", "def"]
|
|
|
- * StringUtils.split("abc def", " ") = ["abc", "def"]
|
|
|
- * StringUtils.split("abc def", " ") = ["abc", "def"]
|
|
|
- * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
|
|
|
- * </pre>
|
|
|
- *
|
|
|
- * @param str the String to parse, may be null
|
|
|
- * @param separatorChars the characters used as the delimiters, {@code null} splits on
|
|
|
- * whitespace
|
|
|
- * @return an array of parsed Strings, {@code null} if null String input
|
|
|
- */
|
|
|
- public static String[] split(final String str, final String separatorChars) {
|
|
|
- List<String> strings = splitWorker(str, separatorChars, -1, false);
|
|
|
- return strings.toArray(new String[strings.size()]);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Performs the logic for the {@code split} and
|
|
|
- * {@code splitPreserveAllTokens} methods that return a maximum array
|
|
|
- * length.
|
|
|
- *
|
|
|
- * @param str the String to parse, may be {@code null}
|
|
|
- * @param separatorChars the separate character
|
|
|
- * @param max the maximum number of elements to include in the array. A zero
|
|
|
- * or negative value implies no limit.
|
|
|
- * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty
|
|
|
- * token separators; if {@code false}, adjacent separators are
|
|
|
- * treated as one separator.
|
|
|
- * @return an array of parsed Strings, {@code null} if null String input
|
|
|
- */
|
|
|
- public static List<String> splitWorker(final String str, final String separatorChars, final int max,
|
|
|
- final boolean preserveAllTokens) {
|
|
|
- // Performance tuned for 2.0 (JDK1.4)
|
|
|
- // Direct code is quicker than StringTokenizer.
|
|
|
- // Also, StringTokenizer uses isSpace() not isWhitespace()
|
|
|
-
|
|
|
- if (str == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- final int len = str.length();
|
|
|
- if (len == 0) {
|
|
|
- return Collections.emptyList();
|
|
|
- }
|
|
|
- final List<String> list = new ArrayList<>();
|
|
|
- int sizePlus1 = 1;
|
|
|
- int i = 0, start = 0;
|
|
|
- boolean match = false;
|
|
|
- boolean lastMatch = false;
|
|
|
- if (separatorChars == null) {
|
|
|
- // Null separator means use whitespace
|
|
|
- while (i < len) {
|
|
|
- if (Character.isWhitespace(str.charAt(i))) {
|
|
|
- if (match || preserveAllTokens) {
|
|
|
- lastMatch = true;
|
|
|
- if (sizePlus1++ == max) {
|
|
|
- i = len;
|
|
|
- lastMatch = false;
|
|
|
- }
|
|
|
- list.add(str.substring(start, i));
|
|
|
- match = false;
|
|
|
- }
|
|
|
- start = ++i;
|
|
|
- continue;
|
|
|
- }
|
|
|
- lastMatch = false;
|
|
|
- match = true;
|
|
|
- i++;
|
|
|
- }
|
|
|
- } else if (separatorChars.length() == 1) {
|
|
|
- // Optimise 1 character case
|
|
|
- final char sep = separatorChars.charAt(0);
|
|
|
- while (i < len) {
|
|
|
- if (str.charAt(i) == sep) {
|
|
|
- if (match || preserveAllTokens) {
|
|
|
- lastMatch = true;
|
|
|
- if (sizePlus1++ == max) {
|
|
|
- i = len;
|
|
|
- lastMatch = false;
|
|
|
- }
|
|
|
- list.add(str.substring(start, i));
|
|
|
- match = false;
|
|
|
- }
|
|
|
- start = ++i;
|
|
|
- continue;
|
|
|
- }
|
|
|
- lastMatch = false;
|
|
|
- match = true;
|
|
|
- i++;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // standard case
|
|
|
- while (i < len) {
|
|
|
- if (separatorChars.indexOf(str.charAt(i)) >= 0) {
|
|
|
- if (match || preserveAllTokens) {
|
|
|
- lastMatch = true;
|
|
|
- if (sizePlus1++ == max) {
|
|
|
- i = len;
|
|
|
- lastMatch = false;
|
|
|
- }
|
|
|
- list.add(str.substring(start, i));
|
|
|
- match = false;
|
|
|
- }
|
|
|
- start = ++i;
|
|
|
- continue;
|
|
|
- }
|
|
|
- lastMatch = false;
|
|
|
- match = true;
|
|
|
- i++;
|
|
|
- }
|
|
|
- }
|
|
|
- if (match || preserveAllTokens && lastMatch) {
|
|
|
- list.add(str.substring(start, i));
|
|
|
- }
|
|
|
- return list;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 是否为CharSequence类型
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param cls
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static Boolean isCharSequence(Class<?> cls) {
|
|
|
- return cls != null && CharSequence.class.isAssignableFrom(cls);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 去除boolean类型is开头的字符串
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param propertyName 字段名
|
|
|
- * @param propertyType 字段类型
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String removeIsPrefixIfBoolean(String propertyName, Class<?> propertyType) {
|
|
|
- if (isBoolean(propertyType) && propertyName.startsWith(IS)) {
|
|
|
- String property = propertyName.replaceFirst(IS, EMPTY);
|
|
|
- if (isEmpty(property)) {
|
|
|
- return propertyName;
|
|
|
- } else {
|
|
|
- String firstCharToLowerStr = firstCharToLower(property);
|
|
|
- return property.equals(firstCharToLowerStr) ? propertyName : firstCharToLowerStr;
|
|
|
- }
|
|
|
- }
|
|
|
- return propertyName;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 是否为CharSequence类型
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param propertyType
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static Boolean isCharSequence(String propertyType) {
|
|
|
- try {
|
|
|
- return isCharSequence(Class.forName(propertyType));
|
|
|
- } catch (ClassNotFoundException e) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 是否为Boolean类型(包含普通类型)
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param propertyCls
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static Boolean isBoolean(Class<?> propertyCls) {
|
|
|
- return propertyCls != null && (boolean.class.isAssignableFrom(propertyCls) || Boolean.class.isAssignableFrom(propertyCls));
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 第一个首字母小写,之后字符大小写的不变<br>
|
|
|
- * StringUtils.firstCharToLower( "UserService" ) = userService
|
|
|
- * StringUtils.firstCharToLower( "UserServiceImpl" ) = userServiceImpl
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param rawString 需要处理的字符串
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String firstCharToLower(String rawString) {
|
|
|
- return prefixToLower(rawString, 1);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 前n个首字母小写,之后字符大小写的不变
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param rawString 需要处理的字符串
|
|
|
- * @param index 多少个字符(从左至右)
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String prefixToLower(String rawString, int index) {
|
|
|
- String beforeChar = rawString.substring(0, index).toLowerCase();
|
|
|
- String afterChar = rawString.substring(index, rawString.length());
|
|
|
- return beforeChar + afterChar;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 删除字符前缀之后,首字母小写,之后字符大小写的不变<br>
|
|
|
- * StringUtils.removePrefixAfterPrefixToLower( "isUser", 2 ) = user
|
|
|
- * StringUtils.removePrefixAfterPrefixToLower( "isUserInfo", 2 ) = userInfo
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param rawString 需要处理的字符串
|
|
|
- * @param index 删除多少个字符(从左至右)
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static String removePrefixAfterPrefixToLower(String rawString, int index) {
|
|
|
- return prefixToLower(rawString.substring(index, rawString.length()), 1);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * <p>
|
|
|
- * 驼峰转连字符<br>
|
|
|
- * StringUtils.camelToHyphen( "managerAdminUserService" ) = manager-admin-user-service
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * @param input
|
|
|
- * @return 以'-'分隔
|
|
|
- * @see <a href="https://github.com/krasa/StringManipulation">document</a>
|
|
|
- */
|
|
|
- public static String camelToHyphen(String input) {
|
|
|
- return wordsToHyphenCase(wordsAndHyphenAndCamelToConstantCase(input));
|
|
|
- }
|
|
|
-
|
|
|
- private static String wordsAndHyphenAndCamelToConstantCase(String input) {
|
|
|
- boolean betweenUpperCases = false;
|
|
|
- boolean containsLowerCase = containsLowerCase(input);
|
|
|
-
|
|
|
- StringBuilder buf = new StringBuilder();
|
|
|
- char previousChar = ' ';
|
|
|
- char[] chars = input.toCharArray();
|
|
|
- for (int i = 0; i < chars.length; i++) {
|
|
|
- char c = chars[i];
|
|
|
- boolean isUpperCaseAndPreviousIsUpperCase = (Character.isUpperCase(previousChar)) && (Character.isUpperCase(c));
|
|
|
- boolean isUpperCaseAndPreviousIsLowerCase = (Character.isLowerCase(previousChar)) && (Character.isUpperCase(c));
|
|
|
-
|
|
|
- boolean previousIsWhitespace = Character.isWhitespace(previousChar);
|
|
|
- boolean lastOneIsNotUnderscore = (buf.length() > 0) && (buf.charAt(buf.length() - 1) != '_');
|
|
|
- boolean isNotUnderscore = c != '_';
|
|
|
- if ((lastOneIsNotUnderscore) && ((isUpperCaseAndPreviousIsLowerCase) || (previousIsWhitespace) || ((betweenUpperCases)
|
|
|
- && (containsLowerCase) && (isUpperCaseAndPreviousIsUpperCase)))) {
|
|
|
- buf.append("_");
|
|
|
- } else if (((separatorAfterDigit) && (Character.isDigit(previousChar))
|
|
|
- && (Character.isLetter(c))) || ((separatorBeforeDigit) && (Character
|
|
|
- .isDigit(c)) && (Character.isLetter(previousChar)))) {
|
|
|
- buf.append('_');
|
|
|
- }
|
|
|
- if ((shouldReplace(c)) && (lastOneIsNotUnderscore)) {
|
|
|
- buf.append('_');
|
|
|
- } else if ((!Character.isWhitespace(c)) && ((isNotUnderscore) || (lastOneIsNotUnderscore))) {
|
|
|
- buf.append(Character.toUpperCase(c));
|
|
|
- }
|
|
|
- previousChar = c;
|
|
|
- }
|
|
|
- if (Character.isWhitespace(previousChar)) {
|
|
|
- buf.append("_");
|
|
|
- }
|
|
|
- return buf.toString();
|
|
|
- }
|
|
|
-
|
|
|
- public static boolean containsLowerCase(String s) {
|
|
|
- for (char c : s.toCharArray()) {
|
|
|
- if (Character.isLowerCase(c)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- private static boolean shouldReplace(char c) {
|
|
|
- return (c == '.') || (c == '_') || (c == '-');
|
|
|
- }
|
|
|
-
|
|
|
- private static String wordsToHyphenCase(String s) {
|
|
|
- StringBuilder buf = new StringBuilder();
|
|
|
- char lastChar = 'a';
|
|
|
- for (char c : s.toCharArray()) {
|
|
|
- if ((Character.isWhitespace(lastChar)) && (!Character.isWhitespace(c))
|
|
|
- && ('-' != c) && (buf.length() > 0)
|
|
|
- && (buf.charAt(buf.length() - 1) != '-')) {
|
|
|
- buf.append("-");
|
|
|
- }
|
|
|
- if ('_' == c) {
|
|
|
- buf.append('-');
|
|
|
- } else if ('.' == c) {
|
|
|
- buf.append('-');
|
|
|
- } else if (!Character.isWhitespace(c)) {
|
|
|
- buf.append(Character.toLowerCase(c));
|
|
|
- }
|
|
|
- lastChar = c;
|
|
|
- }
|
|
|
- if (Character.isWhitespace(lastChar)) {
|
|
|
- buf.append("-");
|
|
|
- }
|
|
|
- return buf.toString();
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * UTF-8 编码格式
|
|
|
+ */
|
|
|
+ public static final String UTF8 = "UTF-8";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 空字符
|
|
|
+ */
|
|
|
+ public static final String EMPTY = "";
|
|
|
+ /**
|
|
|
+ * 字符串 is
|
|
|
+ */
|
|
|
+ public static final String IS = "is";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下划线字符
|
|
|
+ */
|
|
|
+ public static final char UNDERLINE = '_';
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 占位符
|
|
|
+ */
|
|
|
+ public static final String PLACE_HOLDER = "{%s}";
|
|
|
+
|
|
|
+ private static boolean separatorBeforeDigit = false;
|
|
|
+ private static boolean separatorAfterDigit = true;
|
|
|
+
|
|
|
+
|
|
|
+ private StringUtils() {
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * Blob 转为 String 格式
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param blob Blob 对象
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String blob2String(Blob blob) {
|
|
|
+ if (null != blob) {
|
|
|
+ try {
|
|
|
+ byte[] returnValue = blob.getBytes(1, (int) blob.length());
|
|
|
+ return new String(returnValue, UTF8);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new MybatisPlusException("Blob Convert To String Error!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 判断字符串是否为空
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param cs 需要判断字符串
|
|
|
+ * @return 判断结果
|
|
|
+ */
|
|
|
+ public static boolean isEmpty(final CharSequence cs) {
|
|
|
+ int strLen;
|
|
|
+ if (cs == null || (strLen = cs.length()) == 0) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ for (int i = 0; i < strLen; i++) {
|
|
|
+ if (!Character.isWhitespace(cs.charAt(i))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 判断字符串是否不为空
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param cs 需要判断字符串
|
|
|
+ * @return 判断结果
|
|
|
+ */
|
|
|
+ public static boolean isNotEmpty(final CharSequence cs) {
|
|
|
+ return !isEmpty(cs);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 字符串驼峰转下划线格式
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param param 需要转换的字符串
|
|
|
+ * @return 转换好的字符串
|
|
|
+ */
|
|
|
+ public static String camelToUnderline(String param) {
|
|
|
+ if (isEmpty(param)) {
|
|
|
+ return EMPTY;
|
|
|
+ }
|
|
|
+ int len = param.length();
|
|
|
+ StringBuilder sb = new StringBuilder(len);
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ char c = param.charAt(i);
|
|
|
+ if (Character.isUpperCase(c) && i > 0) {
|
|
|
+ sb.append(UNDERLINE);
|
|
|
+ }
|
|
|
+ sb.append(Character.toLowerCase(c));
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 字符串下划线转驼峰格式
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param param 需要转换的字符串
|
|
|
+ * @return 转换好的字符串
|
|
|
+ */
|
|
|
+ public static String underlineToCamel(String param) {
|
|
|
+ if (isEmpty(param)) {
|
|
|
+ return EMPTY;
|
|
|
+ }
|
|
|
+ String temp = param.toLowerCase();
|
|
|
+ int len = temp.length();
|
|
|
+ StringBuilder sb = new StringBuilder(len);
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ char c = temp.charAt(i);
|
|
|
+ if (c == UNDERLINE) {
|
|
|
+ if (++i < len) {
|
|
|
+ sb.append(Character.toUpperCase(temp.charAt(i)));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ sb.append(c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 首字母转换小写
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param param 需要转换的字符串
|
|
|
+ * @return 转换好的字符串
|
|
|
+ */
|
|
|
+ public static String firstToLowerCase(String param) {
|
|
|
+ if (isEmpty(param)) {
|
|
|
+ return EMPTY;
|
|
|
+ }
|
|
|
+ StringBuilder sb = new StringBuilder(param.length());
|
|
|
+ sb.append(param.substring(0, 1).toLowerCase());
|
|
|
+ sb.append(param.substring(1));
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 判断字符串是否为纯大写字母
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param str 要匹配的字符串
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isUpperCase(String str) {
|
|
|
+ return match("^[A-Z]+$", str);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 正则表达式匹配
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param regex 正则表达式字符串
|
|
|
+ * @param str 要匹配的字符串
|
|
|
+ * @return 如果str 符合 regex的正则表达式格式,返回true, 否则返回 false;
|
|
|
+ */
|
|
|
+ public static boolean match(String regex, String str) {
|
|
|
+ Pattern pattern = Pattern.compile(regex);
|
|
|
+ Matcher matcher = pattern.matcher(str);
|
|
|
+ return matcher.matches();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * SQL 参数填充
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param content 填充内容
|
|
|
+ * @param args 填充参数
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String sqlArgsFill(String content, Object... args) {
|
|
|
+ if (StringUtils.isEmpty(content)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (args != null) {
|
|
|
+ int length = args.length;
|
|
|
+ if (length >= 1) {
|
|
|
+ for (int i = 0; i < length; i++) {
|
|
|
+ content = content.replace(String.format(PLACE_HOLDER, i), sqlParam(args[i]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 获取SQL PARAMS字符串
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param obj
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String sqlParam(Object obj) {
|
|
|
+ String repStr;
|
|
|
+ if (obj instanceof Collection) {
|
|
|
+ repStr = StringUtils.quotaMarkList((Collection<?>) obj);
|
|
|
+ } else {
|
|
|
+ repStr = StringUtils.quotaMark(obj);
|
|
|
+ }
|
|
|
+ return repStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 使用单引号包含字符串
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param obj 原字符串
|
|
|
+ * @return 单引号包含的原字符串
|
|
|
+ */
|
|
|
+ public static String quotaMark(Object obj) {
|
|
|
+ String srcStr = String.valueOf(obj);
|
|
|
+ if (obj instanceof CharSequence) {
|
|
|
+ // fix #79
|
|
|
+ return StringEscape.escapeString(srcStr);
|
|
|
+ }
|
|
|
+ return srcStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 使用单引号包含字符串
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param coll 集合
|
|
|
+ * @return 单引号包含的原字符串的集合形式
|
|
|
+ */
|
|
|
+ public static String quotaMarkList(Collection<?> coll) {
|
|
|
+ StringBuilder sqlBuild = new StringBuilder();
|
|
|
+ sqlBuild.append("(");
|
|
|
+ int size = coll.size();
|
|
|
+ int i = 0;
|
|
|
+ Iterator<?> iterator = coll.iterator();
|
|
|
+ while (iterator.hasNext()) {
|
|
|
+ String tempVal = StringUtils.quotaMark(iterator.next());
|
|
|
+ sqlBuild.append(tempVal);
|
|
|
+ if (i + 1 < size) {
|
|
|
+ sqlBuild.append(",");
|
|
|
+ }
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ sqlBuild.append(")");
|
|
|
+ return sqlBuild.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 拼接字符串第二个字符串第一个字母大写
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param concatStr
|
|
|
+ * @param str
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String concatCapitalize(String concatStr, final String str) {
|
|
|
+ if (isEmpty(concatStr)) {
|
|
|
+ concatStr = EMPTY;
|
|
|
+ }
|
|
|
+ int strLen;
|
|
|
+ if (str == null || (strLen = str.length()) == 0) {
|
|
|
+ return str;
|
|
|
+ }
|
|
|
+
|
|
|
+ final char firstChar = str.charAt(0);
|
|
|
+ if (Character.isTitleCase(firstChar)) {
|
|
|
+ // already capitalized
|
|
|
+ return str;
|
|
|
+ }
|
|
|
+
|
|
|
+ StringBuilder sb = new StringBuilder(strLen);
|
|
|
+ sb.append(concatStr);
|
|
|
+ sb.append(Character.toTitleCase(firstChar));
|
|
|
+ sb.append(str.substring(1));
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 字符串第一个字母大写
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param str
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String capitalize(final String str) {
|
|
|
+ return concatCapitalize(null, str);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 判断对象是否为空
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param object
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean checkValNotNull(Object object) {
|
|
|
+ if (object instanceof CharSequence) {
|
|
|
+ return isNotEmpty((CharSequence) object);
|
|
|
+ }
|
|
|
+ return object != null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 判断对象是否为空
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param object
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean checkValNull(Object object) {
|
|
|
+ return !checkValNotNull(object);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 包含大写字母
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param word 待判断字符串
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean containsUpperCase(String word) {
|
|
|
+ for (int i = 0; i < word.length(); i++) {
|
|
|
+ char c = word.charAt(i);
|
|
|
+ if (Character.isUpperCase(c)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 是否为大写命名
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param word 待判断字符串
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isCapitalMode(String word) {
|
|
|
+ return null != word && word.matches("^[0-9A-Z/_]+$");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 是否为驼峰下划线混合命名
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param word 待判断字符串
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isMixedMode(String word) {
|
|
|
+ return Pattern.compile(".*[A-Z]+.*").matcher(word).matches() && Pattern.compile(".*[/_]+.*").matcher(word).matches();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * Check if a String ends with a specified suffix.
|
|
|
+ * </p>
|
|
|
+ * <p>
|
|
|
+ * <p>
|
|
|
+ * <code>null</code>s are handled without exceptions. Two <code>null</code>
|
|
|
+ * references are considered to be equal. The comparison is case sensitive.
|
|
|
+ * </p>
|
|
|
+ * <p>
|
|
|
+ * <pre>
|
|
|
+ * StringUtils.endsWith(null, null) = true
|
|
|
+ * StringUtils.endsWith(null, "abcdef") = false
|
|
|
+ * StringUtils.endsWith("def", null) = false
|
|
|
+ * StringUtils.endsWith("def", "abcdef") = true
|
|
|
+ * StringUtils.endsWith("def", "ABCDEF") = false
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ * @param str the String to check, may be null
|
|
|
+ * @param suffix the suffix to find, may be null
|
|
|
+ * @return <code>true</code> if the String ends with the suffix, case
|
|
|
+ * sensitive, or both <code>null</code>
|
|
|
+ * @see java.lang.String#endsWith(String)
|
|
|
+ * @since 2.4
|
|
|
+ */
|
|
|
+ public static boolean endsWith(String str, String suffix) {
|
|
|
+ return endsWith(str, suffix, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * Case insensitive check if a String ends with a specified suffix.
|
|
|
+ * </p>
|
|
|
+ * <p>
|
|
|
+ * <p>
|
|
|
+ * <code>null</code>s are handled without exceptions. Two <code>null</code>
|
|
|
+ * references are considered to be equal. The comparison is case
|
|
|
+ * insensitive.
|
|
|
+ * </p>
|
|
|
+ * <p>
|
|
|
+ * <pre>
|
|
|
+ * StringUtils.endsWithIgnoreCase(null, null) = true
|
|
|
+ * StringUtils.endsWithIgnoreCase(null, "abcdef") = false
|
|
|
+ * StringUtils.endsWithIgnoreCase("def", null) = false
|
|
|
+ * StringUtils.endsWithIgnoreCase("def", "abcdef") = true
|
|
|
+ * StringUtils.endsWithIgnoreCase("def", "ABCDEF") = false
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ * @param str the String to check, may be null
|
|
|
+ * @param suffix the suffix to find, may be null
|
|
|
+ * @return <code>true</code> if the String ends with the suffix, case
|
|
|
+ * insensitive, or both <code>null</code>
|
|
|
+ * @see java.lang.String#endsWith(String)
|
|
|
+ * @since 2.4
|
|
|
+ */
|
|
|
+ public static boolean endsWithIgnoreCase(String str, String suffix) {
|
|
|
+ return endsWith(str, suffix, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * Check if a String ends with a specified suffix (optionally case
|
|
|
+ * insensitive).
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param str the String to check, may be null
|
|
|
+ * @param suffix the suffix to find, may be null
|
|
|
+ * @param ignoreCase inidicates whether the compare should ignore case (case
|
|
|
+ * insensitive) or not.
|
|
|
+ * @return <code>true</code> if the String starts with the prefix or both
|
|
|
+ * <code>null</code>
|
|
|
+ * @see java.lang.String#endsWith(String)
|
|
|
+ */
|
|
|
+ private static boolean endsWith(String str, String suffix, boolean ignoreCase) {
|
|
|
+ if (str == null || suffix == null) {
|
|
|
+ return (str == null && suffix == null);
|
|
|
+ }
|
|
|
+ if (suffix.length() > str.length()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ int strOffset = str.length() - suffix.length();
|
|
|
+ return str.regionMatches(ignoreCase, strOffset, suffix, 0, suffix.length());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * Splits the provided text into an array, separators specified. This is an
|
|
|
+ * alternative to using StringTokenizer.
|
|
|
+ * </p>
|
|
|
+ * <p>
|
|
|
+ * <p>
|
|
|
+ * The separator is not included in the returned String array. Adjacent
|
|
|
+ * separators are treated as one separator. For more control over the split
|
|
|
+ * use the StrTokenizer class.
|
|
|
+ * </p>
|
|
|
+ * <p>
|
|
|
+ * <p>
|
|
|
+ * A {@code null} input String returns {@code null}. A {@code null}
|
|
|
+ * separatorChars splits on whitespace.
|
|
|
+ * </p>
|
|
|
+ * <p>
|
|
|
+ * <pre>
|
|
|
+ * StringUtils.split(null, *) = null
|
|
|
+ * StringUtils.split("", *) = []
|
|
|
+ * StringUtils.split("abc def", null) = ["abc", "def"]
|
|
|
+ * StringUtils.split("abc def", " ") = ["abc", "def"]
|
|
|
+ * StringUtils.split("abc def", " ") = ["abc", "def"]
|
|
|
+ * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ * @param str the String to parse, may be null
|
|
|
+ * @param separatorChars the characters used as the delimiters, {@code null} splits on
|
|
|
+ * whitespace
|
|
|
+ * @return an array of parsed Strings, {@code null} if null String input
|
|
|
+ */
|
|
|
+ public static String[] split(final String str, final String separatorChars) {
|
|
|
+ List<String> strings = splitWorker(str, separatorChars, -1, false);
|
|
|
+ return strings.toArray(new String[strings.size()]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Performs the logic for the {@code split} and
|
|
|
+ * {@code splitPreserveAllTokens} methods that return a maximum array
|
|
|
+ * length.
|
|
|
+ *
|
|
|
+ * @param str the String to parse, may be {@code null}
|
|
|
+ * @param separatorChars the separate character
|
|
|
+ * @param max the maximum number of elements to include in the array. A zero
|
|
|
+ * or negative value implies no limit.
|
|
|
+ * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty
|
|
|
+ * token separators; if {@code false}, adjacent separators are
|
|
|
+ * treated as one separator.
|
|
|
+ * @return an array of parsed Strings, {@code null} if null String input
|
|
|
+ */
|
|
|
+ public static List<String> splitWorker(final String str, final String separatorChars, final int max,
|
|
|
+ final boolean preserveAllTokens) {
|
|
|
+ // Performance tuned for 2.0 (JDK1.4)
|
|
|
+ // Direct code is quicker than StringTokenizer.
|
|
|
+ // Also, StringTokenizer uses isSpace() not isWhitespace()
|
|
|
+
|
|
|
+ if (str == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ final int len = str.length();
|
|
|
+ if (len == 0) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ final List<String> list = new ArrayList<>();
|
|
|
+ int sizePlus1 = 1;
|
|
|
+ int i = 0, start = 0;
|
|
|
+ boolean match = false;
|
|
|
+ boolean lastMatch = false;
|
|
|
+ if (separatorChars == null) {
|
|
|
+ // Null separator means use whitespace
|
|
|
+ while (i < len) {
|
|
|
+ if (Character.isWhitespace(str.charAt(i))) {
|
|
|
+ if (match || preserveAllTokens) {
|
|
|
+ lastMatch = true;
|
|
|
+ if (sizePlus1++ == max) {
|
|
|
+ i = len;
|
|
|
+ lastMatch = false;
|
|
|
+ }
|
|
|
+ list.add(str.substring(start, i));
|
|
|
+ match = false;
|
|
|
+ }
|
|
|
+ start = ++i;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ lastMatch = false;
|
|
|
+ match = true;
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ } else if (separatorChars.length() == 1) {
|
|
|
+ // Optimise 1 character case
|
|
|
+ final char sep = separatorChars.charAt(0);
|
|
|
+ while (i < len) {
|
|
|
+ if (str.charAt(i) == sep) {
|
|
|
+ if (match || preserveAllTokens) {
|
|
|
+ lastMatch = true;
|
|
|
+ if (sizePlus1++ == max) {
|
|
|
+ i = len;
|
|
|
+ lastMatch = false;
|
|
|
+ }
|
|
|
+ list.add(str.substring(start, i));
|
|
|
+ match = false;
|
|
|
+ }
|
|
|
+ start = ++i;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ lastMatch = false;
|
|
|
+ match = true;
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // standard case
|
|
|
+ while (i < len) {
|
|
|
+ if (separatorChars.indexOf(str.charAt(i)) >= 0) {
|
|
|
+ if (match || preserveAllTokens) {
|
|
|
+ lastMatch = true;
|
|
|
+ if (sizePlus1++ == max) {
|
|
|
+ i = len;
|
|
|
+ lastMatch = false;
|
|
|
+ }
|
|
|
+ list.add(str.substring(start, i));
|
|
|
+ match = false;
|
|
|
+ }
|
|
|
+ start = ++i;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ lastMatch = false;
|
|
|
+ match = true;
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (match || preserveAllTokens && lastMatch) {
|
|
|
+ list.add(str.substring(start, i));
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 是否为CharSequence类型
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param cls
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Boolean isCharSequence(Class<?> cls) {
|
|
|
+ return cls != null && CharSequence.class.isAssignableFrom(cls);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 去除boolean类型is开头的字符串
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param propertyName 字段名
|
|
|
+ * @param propertyType 字段类型
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String removeIsPrefixIfBoolean(String propertyName, Class<?> propertyType) {
|
|
|
+ if (isBoolean(propertyType) && propertyName.startsWith(IS)) {
|
|
|
+ String property = propertyName.replaceFirst(IS, EMPTY);
|
|
|
+ if (isEmpty(property)) {
|
|
|
+ return propertyName;
|
|
|
+ } else {
|
|
|
+ String firstCharToLowerStr = firstCharToLower(property);
|
|
|
+ return property.equals(firstCharToLowerStr) ? propertyName : firstCharToLowerStr;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return propertyName;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 是否为CharSequence类型
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param propertyType
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Boolean isCharSequence(String propertyType) {
|
|
|
+ try {
|
|
|
+ return isCharSequence(Class.forName(propertyType));
|
|
|
+ } catch (ClassNotFoundException e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 是否为Boolean类型(包含普通类型)
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param propertyCls
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Boolean isBoolean(Class<?> propertyCls) {
|
|
|
+ return propertyCls != null && (boolean.class.isAssignableFrom(propertyCls) || Boolean.class.isAssignableFrom(propertyCls));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 第一个首字母小写,之后字符大小写的不变<br>
|
|
|
+ * StringUtils.firstCharToLower( "UserService" ) = userService
|
|
|
+ * StringUtils.firstCharToLower( "UserServiceImpl" ) = userServiceImpl
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param rawString 需要处理的字符串
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String firstCharToLower(String rawString) {
|
|
|
+ return prefixToLower(rawString, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 前n个首字母小写,之后字符大小写的不变
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param rawString 需要处理的字符串
|
|
|
+ * @param index 多少个字符(从左至右)
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String prefixToLower(String rawString, int index) {
|
|
|
+ String beforeChar = rawString.substring(0, index).toLowerCase();
|
|
|
+ String afterChar = rawString.substring(index, rawString.length());
|
|
|
+ return beforeChar + afterChar;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 删除字符前缀之后,首字母小写,之后字符大小写的不变<br>
|
|
|
+ * StringUtils.removePrefixAfterPrefixToLower( "isUser", 2 ) = user
|
|
|
+ * StringUtils.removePrefixAfterPrefixToLower( "isUserInfo", 2 ) = userInfo
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param rawString 需要处理的字符串
|
|
|
+ * @param index 删除多少个字符(从左至右)
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String removePrefixAfterPrefixToLower(String rawString, int index) {
|
|
|
+ return prefixToLower(rawString.substring(index, rawString.length()), 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ * 驼峰转连字符<br>
|
|
|
+ * StringUtils.camelToHyphen( "managerAdminUserService" ) = manager-admin-user-service
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param input
|
|
|
+ * @return 以'-'分隔
|
|
|
+ * @see <a href="https://github.com/krasa/StringManipulation">document</a>
|
|
|
+ */
|
|
|
+ public static String camelToHyphen(String input) {
|
|
|
+ return wordsToHyphenCase(wordsAndHyphenAndCamelToConstantCase(input));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String wordsAndHyphenAndCamelToConstantCase(String input) {
|
|
|
+ boolean betweenUpperCases = false;
|
|
|
+ boolean containsLowerCase = containsLowerCase(input);
|
|
|
+
|
|
|
+ StringBuilder buf = new StringBuilder();
|
|
|
+ char previousChar = ' ';
|
|
|
+ char[] chars = input.toCharArray();
|
|
|
+ for (int i = 0; i < chars.length; i++) {
|
|
|
+ char c = chars[i];
|
|
|
+ boolean isUpperCaseAndPreviousIsUpperCase = (Character.isUpperCase(previousChar)) && (Character.isUpperCase(c));
|
|
|
+ boolean isUpperCaseAndPreviousIsLowerCase = (Character.isLowerCase(previousChar)) && (Character.isUpperCase(c));
|
|
|
+
|
|
|
+ boolean previousIsWhitespace = Character.isWhitespace(previousChar);
|
|
|
+ boolean lastOneIsNotUnderscore = (buf.length() > 0) && (buf.charAt(buf.length() - 1) != '_');
|
|
|
+ boolean isNotUnderscore = c != '_';
|
|
|
+ if ((lastOneIsNotUnderscore) && ((isUpperCaseAndPreviousIsLowerCase) || (previousIsWhitespace) || ((betweenUpperCases)
|
|
|
+ && (containsLowerCase) && (isUpperCaseAndPreviousIsUpperCase)))) {
|
|
|
+ buf.append("_");
|
|
|
+ } else if (((separatorAfterDigit) && (Character.isDigit(previousChar))
|
|
|
+ && (Character.isLetter(c))) || ((separatorBeforeDigit) && (Character
|
|
|
+ .isDigit(c)) && (Character.isLetter(previousChar)))) {
|
|
|
+ buf.append('_');
|
|
|
+ }
|
|
|
+ if ((shouldReplace(c)) && (lastOneIsNotUnderscore)) {
|
|
|
+ buf.append('_');
|
|
|
+ } else if ((!Character.isWhitespace(c)) && ((isNotUnderscore) || (lastOneIsNotUnderscore))) {
|
|
|
+ buf.append(Character.toUpperCase(c));
|
|
|
+ }
|
|
|
+ previousChar = c;
|
|
|
+ }
|
|
|
+ if (Character.isWhitespace(previousChar)) {
|
|
|
+ buf.append("_");
|
|
|
+ }
|
|
|
+ return buf.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean containsLowerCase(String s) {
|
|
|
+ for (char c : s.toCharArray()) {
|
|
|
+ if (Character.isLowerCase(c)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean shouldReplace(char c) {
|
|
|
+ return (c == '.') || (c == '_') || (c == '-');
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String wordsToHyphenCase(String s) {
|
|
|
+ StringBuilder buf = new StringBuilder();
|
|
|
+ char lastChar = 'a';
|
|
|
+ for (char c : s.toCharArray()) {
|
|
|
+ if ((Character.isWhitespace(lastChar)) && (!Character.isWhitespace(c))
|
|
|
+ && ('-' != c) && (buf.length() > 0)
|
|
|
+ && (buf.charAt(buf.length() - 1) != '-')) {
|
|
|
+ buf.append("-");
|
|
|
+ }
|
|
|
+ if ('_' == c) {
|
|
|
+ buf.append('-');
|
|
|
+ } else if ('.' == c) {
|
|
|
+ buf.append('-');
|
|
|
+ } else if (!Character.isWhitespace(c)) {
|
|
|
+ buf.append(Character.toLowerCase(c));
|
|
|
+ }
|
|
|
+ lastChar = c;
|
|
|
+ }
|
|
|
+ if (Character.isWhitespace(lastChar)) {
|
|
|
+ buf.append("-");
|
|
|
+ }
|
|
|
+ return buf.toString();
|
|
|
+ }
|
|
|
}
|