田源
2025-04-03 9b4433fddf5b401edb0aace8a404ac733b122702
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1577 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.utils;
import org.springblade.core.tool.support.StrSpliter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.util.HtmlUtils;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
 * ç»§æ‰¿è‡ªSpring util的工具类,减少jar依赖
 *
 * @author L.cm
 */
public class StringUtil extends org.springframework.util.StringUtils {
   public static final int INDEX_NOT_FOUND = -1;
   /**
    * Check whether the given {@code CharSequence} contains actual <em>text</em>.
    * <p>More specifically, this method returns {@code true} if the
    * {@code CharSequence} is not {@code null}, its length is greater than
    * 0, and it contains at least one non-whitespace character.
    * <pre class="code">
    * StringUtil.isBlank(null) = true
    * StringUtil.isBlank("") = true
    * StringUtil.isBlank(" ") = true
    * StringUtil.isBlank("12345") = false
    * StringUtil.isBlank(" 12345 ") = false
    * </pre>
    *
    * @param cs the {@code CharSequence} to check (may be {@code null})
    * @return {@code true} if the {@code CharSequence} is not {@code null},
    * its length is greater than 0, and it does not contain whitespace only
    * @see Character#isWhitespace
    */
   public static boolean isBlank(final CharSequence cs) {
      return !StringUtil.hasText(cs);
   }
   /**
    * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
    * <pre>
    * StringUtil.isNotBlank(null)     = false
    * StringUtil.isNotBlank("")      = false
    * StringUtil.isNotBlank(" ")      = false
    * StringUtil.isNotBlank("bob")    = true
    * StringUtil.isNotBlank("  bob  ") = true
    * </pre>
    *
    * @param cs the CharSequence to check, may be null
    * @return {@code true} if the CharSequence is
    * not empty and not null and not whitespace
    * @see Character#isWhitespace
    */
   public static boolean isNotBlank(final CharSequence cs) {
      return StringUtil.hasText(cs);
   }
   /**
    * æœ‰ ä»»æ„ ä¸€ä¸ª Blank
    *
    * @param css CharSequence
    * @return boolean
    */
   public static boolean isAnyBlank(final CharSequence... css) {
      if (ObjectUtil.isEmpty(css)) {
         return true;
      }
      return Stream.of(css).anyMatch(StringUtil::isBlank);
   }
   /**
    * æ˜¯å¦å…¨éž Blank
    *
    * @param css CharSequence
    * @return boolean
    */
   public static boolean isNoneBlank(final CharSequence... css) {
      if (ObjectUtil.isEmpty(css)) {
         return false;
      }
      return Stream.of(css).allMatch(StringUtil::isNotBlank);
   }
   /**
    * æ˜¯å¦å…¨ä¸º Blank
    *
    * @param css CharSequence
    * @return boolean
    */
   public static boolean isAllBlank(final CharSequence... css) {
      return Stream.of(css).allMatch(StringUtil::isBlank);
   }
   /**
    * åˆ¤æ–­ä¸€ä¸ªå­—符串是否是数字
    *
    * @param cs the CharSequence to check, may be null
    * @return {boolean}
    */
   public static boolean isNumeric(final CharSequence cs) {
      if (isBlank(cs)) {
         return false;
      }
      for (int i = cs.length(); --i >= 0; ) {
         int chr = cs.charAt(i);
         if (chr < 48 || chr > 57) {
            return false;
         }
      }
      return true;
   }
   /**
    * å°†å­—符串中特定模式的字符转换成map中对应的值
    * <p>
    * use: format("my name is ${name}, and i like ${like}!", {"name":"L.cm", "like": "Java"})
    *
    * @param message éœ€è¦è½¬æ¢çš„字符串
    * @param params  è½¬æ¢æ‰€éœ€çš„键值对集合
    * @return è½¬æ¢åŽçš„字符串
    */
   public static String format(@Nullable String message, @Nullable Map<String, ?> params) {
      // message ä¸º null è¿”回空字符串
      if (message == null) {
         return StringPool.EMPTY;
      }
      // å‚数为 null æˆ–者为空
      if (params == null || params.isEmpty()) {
         return message;
      }
      // æ›¿æ¢å˜é‡
      StringBuilder sb = new StringBuilder((int) (message.length() * 1.5));
      int cursor = 0;
      for (int start, end; (start = message.indexOf(StringPool.DOLLAR_LEFT_BRACE, cursor)) != -1 && (end = message.indexOf(StringPool.RIGHT_BRACE, start)) != -1; ) {
         sb.append(message, cursor, start);
         String key = message.substring(start + 2, end);
         Object value = params.get(StringUtil.trimWhitespace(key));
         sb.append(value == null ? StringPool.EMPTY : value);
         cursor = end + 1;
      }
      sb.append(message.substring(cursor));
      return sb.toString();
   }
   /**
    * åŒ log æ ¼å¼çš„ format è§„则
    * <p>
    * use: format("my name is {}, and i like {}!", "L.cm", "Java")
    *
    * @param message   éœ€è¦è½¬æ¢çš„字符串
    * @param arguments éœ€è¦æ›¿æ¢çš„变量
    * @return è½¬æ¢åŽçš„字符串
    */
   public static String format(@Nullable String message, @Nullable Object... arguments) {
      // message ä¸º null è¿”回空字符串
      if (message == null) {
         return StringPool.EMPTY;
      }
      // å‚数为 null æˆ–者为空
      if (arguments == null || arguments.length == 0) {
         return message;
      }
      StringBuilder sb = new StringBuilder((int) (message.length() * 1.5));
      int cursor = 0;
      int index = 0;
      int argsLength = arguments.length;
      for (int start, end; (start = message.indexOf('{', cursor)) != -1 && (end = message.indexOf('}', start)) != -1 && index < argsLength; ) {
         sb.append(message, cursor, start);
         sb.append(arguments[index]);
         cursor = end + 1;
         index++;
      }
      sb.append(message.substring(cursor));
      return sb.toString();
   }
   /**
    * æ ¼å¼åŒ–执行时间,单位为 ms å’Œ s,保留三位小数
    *
    * @param nanos çº³ç§’
    * @return æ ¼å¼åŒ–后的时间
    */
   public static String format(long nanos) {
      if (nanos < 1) {
         return "0ms";
      }
      double millis = (double) nanos / (1000 * 1000);
      // ä¸å¤Ÿ 1 ms,最小单位为 ms
      if (millis > 1000) {
         return String.format("%.3fs", millis / 1000);
      } else {
         return String.format("%.3fms", millis);
      }
   }
   /**
    * Convert a {@code Collection} into a delimited {@code String} (e.g., CSV).
    * <p>Useful for {@code toString()} implementations.
    *
    * @param coll the {@code Collection} to convert
    * @return the delimited {@code String}
    */
   public static String join(Collection<?> coll) {
      return StringUtil.collectionToCommaDelimitedString(coll);
   }
   /**
    * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV).
    * <p>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 join(Collection<?> coll, String delim) {
      return StringUtil.collectionToDelimitedString(coll, delim);
   }
   /**
    * Convert a {@code String} array into a comma delimited {@code String}
    * (i.e., CSV).
    * <p>Useful for {@code toString()} implementations.
    *
    * @param arr the array to display
    * @return the delimited {@code String}
    */
   public static String join(Object[] arr) {
      return StringUtil.arrayToCommaDelimitedString(arr);
   }
   /**
    * Convert a {@code String} array into a delimited {@code String} (e.g. CSV).
    * <p>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 join(Object[] arr, String delim) {
      return StringUtil.arrayToDelimitedString(arr, delim);
   }
   /**
    * å­—符串是否符合指定的 è¡¨è¾¾å¼
    *
    * <p>
    * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy"
    * </p>
    *
    * @param pattern è¡¨è¾¾å¼
    * @param str     å­—符串
    * @return æ˜¯å¦åŒ¹é…
    */
   public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) {
      return PatternMatchUtils.simpleMatch(pattern, str);
   }
   /**
    * å­—符串是否符合指定的 è¡¨è¾¾å¼
    *
    * <p>
    * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy"
    * </p>
    *
    * @param patterns è¡¨è¾¾å¼ æ•°ç»„
    * @param str      å­—符串
    * @return æ˜¯å¦åŒ¹é…
    */
   public static boolean simpleMatch(@Nullable String[] patterns, String str) {
      return PatternMatchUtils.simpleMatch(patterns, str);
   }
   /**
    * ç”Ÿæˆuuid
    *
    * @return UUID
    */
   public static String randomUUID() {
      ThreadLocalRandom random = ThreadLocalRandom.current();
      return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY);
   }
   /**
    * è½¬ä¹‰HTML用于安全过滤
    *
    * @param html html
    * @return {String}
    */
   public static String escapeHtml(String html) {
      return StringUtil.isBlank(html) ? StringPool.EMPTY : HtmlUtils.htmlEscape(html);
   }
   /**
    * æ¸…理字符串,清理出某些不可见字符
    *
    * @param txt å­—符串
    * @return {String}
    */
   public static String cleanChars(String txt) {
      return txt.replaceAll("[ ã€€`·•�\\f\\t\\v\\s]", "");
   }
   /**
    * ç‰¹æ®Šå­—符正则,sql特殊字符和空白符
    */
   private final static Pattern SPECIAL_CHARS_REGEX = Pattern.compile("[`'\"|/,;()-+*%#·•� \\s]");
   /**
    * æ¸…理字符串,清理出某些不可见字符和一些sql特殊字符
    *
    * @param txt æ–‡æœ¬
    * @return {String}
    */
   @Nullable
   public static String cleanText(@Nullable String txt) {
      if (txt == null) {
         return null;
      }
      return SPECIAL_CHARS_REGEX.matcher(txt).replaceAll(StringPool.EMPTY);
   }
   /**
    * èŽ·å–æ ‡è¯†ç¬¦ï¼Œç”¨äºŽå‚æ•°æ¸…ç†
    *
    * @param param å‚æ•°
    * @return æ¸…理后的标识符
    */
   @Nullable
   public static String cleanIdentifier(@Nullable String param) {
      if (param == null) {
         return null;
      }
      StringBuilder paramBuilder = new StringBuilder();
      for (int i = 0; i < param.length(); i++) {
         char c = param.charAt(i);
         if (Character.isJavaIdentifierPart(c)) {
            paramBuilder.append(c);
         }
      }
      return paramBuilder.toString();
   }
   /**
    * éšæœºæ•°ç”Ÿæˆ
    *
    * @param count å­—符长度
    * @return éšæœºæ•°
    */
   public static String random(int count) {
      return StringUtil.random(count, RandomType.ALL);
   }
   /**
    * éšæœºæ•°ç”Ÿæˆ
    *
    * @param count      å­—符长度
    * @param randomType éšæœºæ•°ç±»åˆ«
    * @return éšæœºæ•°
    */
   public static String random(int count, RandomType randomType) {
      if (count == 0) {
         return StringPool.EMPTY;
      }
      Assert.isTrue(count > 0, "Requested random string length " + count + " is less than 0.");
      final Random random = Holder.SECURE_RANDOM;
      char[] buffer = new char[count];
      for (int i = 0; i < count; i++) {
         String factor = randomType.getFactor();
         buffer[i] = factor.charAt(random.nextInt(factor.length()));
      }
      return new String(buffer);
   }
   /**
    * æœ‰åºçš„æ ¼å¼åŒ–文本,使用{number}做为占位符<br>
    * ä¾‹ï¼š<br>
    * é€šå¸¸ä½¿ç”¨ï¼šformat("this is {0} for {1}", "a", "b") =》 this is a for b<br>
    *
    * @param pattern   æ–‡æœ¬æ ¼å¼
    * @param arguments å‚æ•°
    * @return æ ¼å¼åŒ–后的文本
    */
   public static String indexedFormat(CharSequence pattern, Object... arguments) {
      return MessageFormat.format(pattern.toString(), arguments);
   }
   /**
    * æ ¼å¼åŒ–文本,使用 {varName} å ä½<br>
    * map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=》 aValue and bValue
    *
    * @param template æ–‡æœ¬æ¨¡æ¿ï¼Œè¢«æ›¿æ¢çš„部分用 {key} è¡¨ç¤º
    * @param map      å‚数值对
    * @return æ ¼å¼åŒ–后的文本
    */
   public static String format(CharSequence template, Map<?, ?> map) {
      if (null == template) {
         return null;
      }
      if (null == map || map.isEmpty()) {
         return template.toString();
      }
      String template2 = template.toString();
      for (Map.Entry<?, ?> entry : map.entrySet()) {
         template2 = template2.replace("{" + entry.getKey() + "}", Func.toStr(entry.getValue()));
      }
      return template2;
   }
   /**
    * åˆ‡åˆ†å­—符串,不去除切分后每个元素两边的空白符,不去除空白项
    *
    * @param str       è¢«åˆ‡åˆ†çš„字符串
    * @param separator åˆ†éš”符字符
    * @param limit     é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
    * @return åˆ‡åˆ†åŽçš„集合
    */
   public static List<String> split(CharSequence str, char separator, int limit) {
      return split(str, separator, limit, false, false);
   }
   /**
    * åˆ†å‰² å­—符串 åˆ é™¤å¸¸è§ ç©ºç™½ç¬¦
    *
    * @param str       å­—符串
    * @param delimiter åˆ†å‰²ç¬¦
    * @return å­—符串数组
    */
   public static String[] splitTrim(@Nullable String str, @Nullable String delimiter) {
      return StringUtil.delimitedListToStringArray(str, delimiter, " \t\n\n\f");
   }
   /**
    * åˆ‡åˆ†å­—符串,去除切分后每个元素两边的空白符,去除空白项
    *
    * @param str       è¢«åˆ‡åˆ†çš„字符串
    * @param separator åˆ†éš”符字符
    * @return åˆ‡åˆ†åŽçš„集合
    * @since 3.1.2
    */
   public static List<String> splitTrim(CharSequence str, char separator) {
      return splitTrim(str, separator, -1);
   }
   /**
    * åˆ‡åˆ†å­—符串,去除切分后每个元素两边的空白符,去除空白项
    *
    * @param str       è¢«åˆ‡åˆ†çš„字符串
    * @param separator åˆ†éš”符字符
    * @return åˆ‡åˆ†åŽçš„集合
    * @since 3.2.0
    */
   public static List<String> splitTrim(CharSequence str, CharSequence separator) {
      return splitTrim(str, separator, -1);
   }
   /**
    * åˆ‡åˆ†å­—符串,去除切分后每个元素两边的空白符,去除空白项
    *
    * @param str       è¢«åˆ‡åˆ†çš„字符串
    * @param separator åˆ†éš”符字符
    * @param limit     é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
    * @return åˆ‡åˆ†åŽçš„集合
    * @since 3.1.0
    */
   public static List<String> splitTrim(CharSequence str, char separator, int limit) {
      return split(str, separator, limit, true, true);
   }
   /**
    * åˆ‡åˆ†å­—符串,去除切分后每个元素两边的空白符,去除空白项
    *
    * @param str       è¢«åˆ‡åˆ†çš„字符串
    * @param separator åˆ†éš”符字符
    * @param limit     é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
    * @return åˆ‡åˆ†åŽçš„集合
    * @since 3.2.0
    */
   public static List<String> splitTrim(CharSequence str, CharSequence separator, int limit) {
      return split(str, separator, limit, true, true);
   }
   /**
    * åˆ‡åˆ†å­—符串,不限制分片数量
    *
    * @param str         è¢«åˆ‡åˆ†çš„字符串
    * @param separator   åˆ†éš”符字符
    * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
    * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
    * @return åˆ‡åˆ†åŽçš„集合
    * @since 3.0.8
    */
   public static List<String> split(CharSequence str, char separator, boolean isTrim, boolean ignoreEmpty) {
      return split(str, separator, 0, isTrim, ignoreEmpty);
   }
   /**
    * åˆ‡åˆ†å­—符串
    *
    * @param str         è¢«åˆ‡åˆ†çš„字符串
    * @param separator   åˆ†éš”符字符
    * @param limit       é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
    * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
    * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
    * @return åˆ‡åˆ†åŽçš„集合
    * @since 3.0.8
    */
   public static List<String> split(CharSequence str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
      if (null == str) {
         return new ArrayList<>(0);
      }
      return StrSpliter.split(str.toString(), separator, limit, isTrim, ignoreEmpty);
   }
   /**
    * åˆ‡åˆ†å­—符串
    *
    * @param str         è¢«åˆ‡åˆ†çš„字符串
    * @param separator   åˆ†éš”符字符
    * @param limit       é™åˆ¶åˆ†ç‰‡æ•°ï¼Œ-1不限制
    * @param isTrim      æ˜¯å¦åŽ»é™¤åˆ‡åˆ†å­—ç¬¦ä¸²åŽæ¯ä¸ªå…ƒç´ ä¸¤è¾¹çš„ç©ºæ ¼
    * @param ignoreEmpty æ˜¯å¦å¿½ç•¥ç©ºä¸²
    * @return åˆ‡åˆ†åŽçš„集合
    * @since 3.2.0
    */
   public static List<String> split(CharSequence str, CharSequence separator, int limit, boolean isTrim, boolean ignoreEmpty) {
      if (null == str) {
         return new ArrayList<>(0);
      }
      final String separatorStr = (null == separator) ? null : separator.toString();
      return StrSpliter.split(str.toString(), separatorStr, limit, isTrim, ignoreEmpty);
   }
   /**
    * åˆ‡åˆ†å­—符串
    *
    * @param str       è¢«åˆ‡åˆ†çš„字符串
    * @param separator åˆ†éš”符
    * @return å­—符串
    */
   public static String[] split(CharSequence str, CharSequence separator) {
      if (str == null) {
         return new String[]{};
      }
      final String separatorStr = (null == separator) ? null : separator.toString();
      return StrSpliter.splitToArray(str.toString(), separatorStr, 0, false, false);
   }
   /**
    * æ ¹æ®ç»™å®šé•¿åº¦ï¼Œå°†ç»™å®šå­—符串截取为多个部分
    *
    * @param str å­—符串
    * @param len æ¯ä¸€ä¸ªå°èŠ‚çš„é•¿åº¦
    * @return æˆªå–后的字符串数组
    * @see StrSpliter#splitByLength(String, int)
    */
   public static String[] split(CharSequence str, int len) {
      if (null == str) {
         return new String[]{};
      }
      return StrSpliter.splitByLength(str.toString(), len);
   }
   /**
    * æŒ‡å®šå­—符是否在字符串中出现过
    *
    * @param str        å­—符串
    * @param searchChar è¢«æŸ¥æ‰¾çš„字符
    * @return æ˜¯å¦åŒ…含
    * @since 3.1.2
    */
   public static boolean contains(CharSequence str, char searchChar) {
      return indexOf(str, searchChar) > -1;
   }
   /**
    * æŸ¥æ‰¾æŒ‡å®šå­—符串是否包含指定字符串列表中的任意一个字符串
    *
    * @param str      æŒ‡å®šå­—符串
    * @param testStrs éœ€è¦æ£€æŸ¥çš„字符串数组
    * @return æ˜¯å¦åŒ…含任意一个字符串
    * @since 3.2.0
    */
   public static boolean containsAny(CharSequence str, CharSequence... testStrs) {
      return null != getContainsStr(str, testStrs);
   }
   /**
    * æŸ¥æ‰¾æŒ‡å®šå­—符串是否包含指定字符串列表中的任意一个字符串,如果包含返回找到的第一个字符串
    *
    * @param str      æŒ‡å®šå­—符串
    * @param testStrs éœ€è¦æ£€æŸ¥çš„字符串数组
    * @return è¢«åŒ…含的第一个字符串
    * @since 3.2.0
    */
   public static String getContainsStr(CharSequence str, CharSequence... testStrs) {
      if (isEmpty(str) || Func.isEmpty(testStrs)) {
         return null;
      }
      for (CharSequence checkStr : testStrs) {
         if (str.toString().contains(checkStr)) {
            return checkStr.toString();
         }
      }
      return null;
   }
   /**
    * æ˜¯å¦åŒ…含特定字符,忽略大小写,如果给定两个参数都为<code>null</code>,返回true
    *
    * @param str     è¢«æ£€æµ‹å­—符串
    * @param testStr è¢«æµ‹è¯•是否包含的字符串
    * @return æ˜¯å¦åŒ…含
    */
   public static boolean containsIgnoreCase(CharSequence str, CharSequence testStr) {
      if (null == str) {
         // å¦‚果被监测字符串和
         return null == testStr;
      }
      return str.toString().toLowerCase().contains(testStr.toString().toLowerCase());
   }
   /**
    * æŸ¥æ‰¾æŒ‡å®šå­—符串是否包含指定字符串列表中的任意一个字符串<br>
    * å¿½ç•¥å¤§å°å†™
    *
    * @param str      æŒ‡å®šå­—符串
    * @param testStrs éœ€è¦æ£€æŸ¥çš„字符串数组
    * @return æ˜¯å¦åŒ…含任意一个字符串
    * @since 3.2.0
    */
   public static boolean containsAnyIgnoreCase(CharSequence str, CharSequence... testStrs) {
      return null != getContainsStrIgnoreCase(str, testStrs);
   }
   /**
    * æŸ¥æ‰¾æŒ‡å®šå­—符串是否包含指定字符串列表中的任意一个字符串,如果包含返回找到的第一个字符串<br>
    * å¿½ç•¥å¤§å°å†™
    *
    * @param str      æŒ‡å®šå­—符串
    * @param testStrs éœ€è¦æ£€æŸ¥çš„字符串数组
    * @return è¢«åŒ…含的第一个字符串
    * @since 3.2.0
    */
   public static String getContainsStrIgnoreCase(CharSequence str, CharSequence... testStrs) {
      if (isEmpty(str) || Func.isEmpty(testStrs)) {
         return null;
      }
      for (CharSequence testStr : testStrs) {
         if (containsIgnoreCase(str, testStr)) {
            return testStr.toString();
         }
      }
      return null;
   }
   /**
    * æ”¹è¿›JDK subString<br>
    * index从0开始计算,最后一个字符为-1<br>
    * å¦‚æžœfrom和to位置一样,返回 "" <br>
    * å¦‚æžœfrom或to为负数,则按照length从后向前数位置,如果绝对值大于字符串长度,则from归到0,to归到length<br>
    * å¦‚果经过修正的index中from大于to,则互换from和to example: <br>
    * abcdefgh 2 3 =》 c <br>
    * abcdefgh 2 -3 =》 cde <br>
    *
    * @param str       String
    * @param fromIndex å¼€å§‹çš„index(包括)
    * @param toIndex   ç»“束的index(不包括)
    * @return å­—串
    */
   public static String sub(CharSequence str, int fromIndex, int toIndex) {
      if (isEmpty(str)) {
         return StringPool.EMPTY;
      }
      int len = str.length();
      if (fromIndex < 0) {
         fromIndex = len + fromIndex;
         if (fromIndex < 0) {
            fromIndex = 0;
         }
      } else if (fromIndex > len) {
         fromIndex = len;
      }
      if (toIndex < 0) {
         toIndex = len + toIndex;
         if (toIndex < 0) {
            toIndex = len;
         }
      } else if (toIndex > len) {
         toIndex = len;
      }
      if (toIndex < fromIndex) {
         int tmp = fromIndex;
         fromIndex = toIndex;
         toIndex = tmp;
      }
      if (fromIndex == toIndex) {
         return StringPool.EMPTY;
      }
      return str.toString().substring(fromIndex, toIndex);
   }
   /**
    * æˆªå–分隔字符串之前的字符串,不包括分隔字符串<br>
    * å¦‚果给定的字符串为空串(null或"")或者分隔字符串为null,返回原字符串<br>
    * å¦‚果分隔字符串为空串"",则返回空串,如果分隔字符串未找到,返回原字符串
    * <p>
    * æ —子:
    *
    * <pre>
    * StringUtil.subBefore(null, *)      = null
    * StringUtil.subBefore("", *)        = ""
    * StringUtil.subBefore("abc", "a")   = ""
    * StringUtil.subBefore("abcba", "b") = "a"
    * StringUtil.subBefore("abc", "c")   = "ab"
    * StringUtil.subBefore("abc", "d")   = "abc"
    * StringUtil.subBefore("abc", "")    = ""
    * StringUtil.subBefore("abc", null)  = "abc"
    * </pre>
    *
    * @param string          è¢«æŸ¥æ‰¾çš„字符串
    * @param separator       åˆ†éš”字符串(不包括)
    * @param isLastSeparator æ˜¯å¦æŸ¥æ‰¾æœ€åŽä¸€ä¸ªåˆ†éš”字符串(多次出现分隔字符串时选取最后一个),true为选取最后一个
    * @return åˆ‡å‰²åŽçš„字符串
    * @since 3.1.1
    */
   public static String subBefore(CharSequence string, CharSequence separator, boolean isLastSeparator) {
      if (isEmpty(string) || separator == null) {
         return null == string ? null : string.toString();
      }
      final String str = string.toString();
      final String sep = separator.toString();
      if (sep.isEmpty()) {
         return StringPool.EMPTY;
      }
      final int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep);
      if (pos == INDEX_NOT_FOUND) {
         return str;
      }
      return str.substring(0, pos);
   }
   /**
    * æˆªå–分隔字符串之后的字符串,不包括分隔字符串<br>
    * å¦‚果给定的字符串为空串(null或""),返回原字符串<br>
    * å¦‚果分隔字符串为空串(null或""),则返回空串,如果分隔字符串未找到,返回空串
    * <p>
    * æ —子:
    *
    * <pre>
    * StringUtil.subAfter(null, *)      = null
    * StringUtil.subAfter("", *)        = ""
    * StringUtil.subAfter(*, null)      = ""
    * StringUtil.subAfter("abc", "a")   = "bc"
    * StringUtil.subAfter("abcba", "b") = "cba"
    * StringUtil.subAfter("abc", "c")   = ""
    * StringUtil.subAfter("abc", "d")   = ""
    * StringUtil.subAfter("abc", "")    = "abc"
    * </pre>
    *
    * @param string          è¢«æŸ¥æ‰¾çš„字符串
    * @param separator       åˆ†éš”字符串(不包括)
    * @param isLastSeparator æ˜¯å¦æŸ¥æ‰¾æœ€åŽä¸€ä¸ªåˆ†éš”字符串(多次出现分隔字符串时选取最后一个),true为选取最后一个
    * @return åˆ‡å‰²åŽçš„字符串
    * @since 3.1.1
    */
   public static String subAfter(CharSequence string, CharSequence separator, boolean isLastSeparator) {
      if (isEmpty(string)) {
         return null == string ? null : string.toString();
      }
      if (separator == null) {
         return StringPool.EMPTY;
      }
      final String str = string.toString();
      final String sep = separator.toString();
      final int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep);
      if (pos == INDEX_NOT_FOUND) {
         return StringPool.EMPTY;
      }
      return str.substring(pos + separator.length());
   }
   /**
    * æˆªå–指定字符串中间部分,不包括标识字符串<br>
    * <p>
    * æ —子:
    *
    * <pre>
    * StringUtil.subBetween("wx[b]yz", "[", "]") = "b"
    * StringUtil.subBetween(null, *, *)          = null
    * StringUtil.subBetween(*, null, *)          = null
    * StringUtil.subBetween(*, *, null)          = null
    * StringUtil.subBetween("", "", "")          = ""
    * StringUtil.subBetween("", "", "]")         = null
    * StringUtil.subBetween("", "[", "]")        = null
    * StringUtil.subBetween("yabcz", "", "")     = ""
    * StringUtil.subBetween("yabcz", "y", "z")   = "abc"
    * StringUtil.subBetween("yabczyabcz", "y", "z")   = "abc"
    * </pre>
    *
    * @param str    è¢«åˆ‡å‰²çš„字符串
    * @param before æˆªå–开始的字符串标识
    * @param after  æˆªå–到的字符串标识
    * @return æˆªå–后的字符串
    * @since 3.1.1
    */
   public static String subBetween(CharSequence str, CharSequence before, CharSequence after) {
      if (str == null || before == null || after == null) {
         return null;
      }
      final String str2 = str.toString();
      final String before2 = before.toString();
      final String after2 = after.toString();
      final int start = str2.indexOf(before2);
      if (start != INDEX_NOT_FOUND) {
         final int end = str2.indexOf(after2, start + before2.length());
         if (end != INDEX_NOT_FOUND) {
            return str2.substring(start + before2.length(), end);
         }
      }
      return null;
   }
   /**
    * æˆªå–指定字符串中间部分,不包括标识字符串<br>
    * <p>
    * æ —子:
    *
    * <pre>
    * StringUtil.subBetween(null, *)            = null
    * StringUtil.subBetween("", "")             = ""
    * StringUtil.subBetween("", "tag")          = null
    * StringUtil.subBetween("tagabctag", null)  = null
    * StringUtil.subBetween("tagabctag", "")    = ""
    * StringUtil.subBetween("tagabctag", "tag") = "abc"
    * </pre>
    *
    * @param str            è¢«åˆ‡å‰²çš„字符串
    * @param beforeAndAfter æˆªå–开始和结束的字符串标识
    * @return æˆªå–后的字符串
    * @since 3.1.1
    */
   public static String subBetween(CharSequence str, CharSequence beforeAndAfter) {
      return subBetween(str, beforeAndAfter, beforeAndAfter);
   }
   /**
    * åŽ»æŽ‰æŒ‡å®šå‰ç¼€
    *
    * @param str    å­—符串
    * @param prefix å‰ç¼€
    * @return åˆ‡æŽ‰åŽçš„字符串,若前缀不是 preffix, è¿”回原字符串
    */
   public static String removePrefix(CharSequence str, CharSequence prefix) {
      if (isEmpty(str) || isEmpty(prefix)) {
         return StringPool.EMPTY;
      }
      final String str2 = str.toString();
      if (str2.startsWith(prefix.toString())) {
         return subSuf(str2, prefix.length());
      }
      return str2;
   }
   /**
    * å¿½ç•¥å¤§å°å†™åŽ»æŽ‰æŒ‡å®šå‰ç¼€
    *
    * @param str    å­—符串
    * @param prefix å‰ç¼€
    * @return åˆ‡æŽ‰åŽçš„字符串,若前缀不是 prefix, è¿”回原字符串
    */
   public static String removePrefixIgnoreCase(CharSequence str, CharSequence prefix) {
      if (isEmpty(str) || isEmpty(prefix)) {
         return StringPool.EMPTY;
      }
      final String str2 = str.toString();
      if (str2.toLowerCase().startsWith(prefix.toString().toLowerCase())) {
         return subSuf(str2, prefix.length());
      }
      return str2;
   }
   /**
    * åŽ»æŽ‰æŒ‡å®šåŽç¼€
    *
    * @param str    å­—符串
    * @param suffix åŽç¼€
    * @return åˆ‡æŽ‰åŽçš„字符串,若后缀不是 suffix, è¿”回原字符串
    */
   public static String removeSuffix(CharSequence str, CharSequence suffix) {
      if (isEmpty(str) || isEmpty(suffix)) {
         return StringPool.EMPTY;
      }
      final String str2 = str.toString();
      if (str2.endsWith(suffix.toString())) {
         return subPre(str2, str2.length() - suffix.length());
      }
      return str2;
   }
   /**
    * åŽ»æŽ‰æŒ‡å®šåŽç¼€ï¼Œå¹¶å°å†™é¦–å­—æ¯
    *
    * @param str    å­—符串
    * @param suffix åŽç¼€
    * @return åˆ‡æŽ‰åŽçš„字符串,若后缀不是 suffix, è¿”回原字符串
    */
   public static String removeSufAndLowerFirst(CharSequence str, CharSequence suffix) {
      return firstCharToLower(removeSuffix(str, suffix));
   }
   /**
    * å¿½ç•¥å¤§å°å†™åŽ»æŽ‰æŒ‡å®šåŽç¼€
    *
    * @param str    å­—符串
    * @param suffix åŽç¼€
    * @return åˆ‡æŽ‰åŽçš„字符串,若后缀不是 suffix, è¿”回原字符串
    */
   public static String removeSuffixIgnoreCase(CharSequence str, CharSequence suffix) {
      if (isEmpty(str) || isEmpty(suffix)) {
         return StringPool.EMPTY;
      }
      final String str2 = str.toString();
      if (str2.toLowerCase().endsWith(suffix.toString().toLowerCase())) {
         return subPre(str2, str2.length() - suffix.length());
      }
      return str2;
   }
   /**
    * é¦–字母变小写
    *
    * @param str å­—符串
    * @return {String}
    */
   public static String firstCharToLower(String str) {
      char firstChar = str.charAt(0);
      if (firstChar >= CharPool.UPPER_A && firstChar <= CharPool.UPPER_Z) {
         char[] arr = str.toCharArray();
         arr[0] += (CharPool.LOWER_A - CharPool.UPPER_A);
         return new String(arr);
      }
      return str;
   }
   /**
    * é¦–字母变大写
    *
    * @param str å­—符串
    * @return {String}
    */
   public static String firstCharToUpper(String str) {
      char firstChar = str.charAt(0);
      if (firstChar >= CharPool.LOWER_A && firstChar <= CharPool.LOWER_Z) {
         char[] arr = str.toCharArray();
         arr[0] -= (CharPool.LOWER_A - CharPool.UPPER_A);
         return new String(arr);
      }
      return str;
   }
   /**
    * åˆ‡å‰²æŒ‡å®šä½ç½®ä¹‹å‰éƒ¨åˆ†çš„字符串
    *
    * @param string  å­—符串
    * @param toIndex åˆ‡å‰²åˆ°çš„位置(不包括)
    * @return åˆ‡å‰²åŽçš„剩余的前半部分字符串
    */
   public static String subPre(CharSequence string, int toIndex) {
      return sub(string, 0, toIndex);
   }
   /**
    * åˆ‡å‰²æŒ‡å®šä½ç½®ä¹‹åŽéƒ¨åˆ†çš„字符串
    *
    * @param string    å­—符串
    * @param fromIndex åˆ‡å‰²å¼€å§‹çš„位置(包括)
    * @return åˆ‡å‰²åŽåŽå‰©ä½™çš„后半部分字符串
    */
   public static String subSuf(CharSequence string, int fromIndex) {
      if (isEmpty(string)) {
         return null;
      }
      return sub(string, fromIndex, string.length());
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找指定字符
    *
    * @param str        å­—符串
    * @param searchChar è¢«æŸ¥æ‰¾çš„字符
    * @return ä½ç½®
    */
   public static int indexOf(final CharSequence str, char searchChar) {
      return indexOf(str, searchChar, 0);
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找指定字符
    *
    * @param str        å­—符串
    * @param searchChar è¢«æŸ¥æ‰¾çš„字符
    * @param start      èµ·å§‹ä½ç½®ï¼Œå¦‚果小于0,从0开始查找
    * @return ä½ç½®
    */
   public static int indexOf(final CharSequence str, char searchChar, int start) {
      if (str instanceof String) {
         return ((String) str).indexOf(searchChar, start);
      } else {
         return indexOf(str, searchChar, start, -1);
      }
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找指定字符
    *
    * @param str        å­—符串
    * @param searchChar è¢«æŸ¥æ‰¾çš„字符
    * @param start      èµ·å§‹ä½ç½®ï¼Œå¦‚果小于0,从0开始查找
    * @param end        ç»ˆæ­¢ä½ç½®ï¼Œå¦‚果超过str.length()则默认查找到字符串末尾
    * @return ä½ç½®
    */
   public static int indexOf(final CharSequence str, char searchChar, int start, int end) {
      final int len = str.length();
      if (start < 0 || start > len) {
         start = 0;
      }
      if (end > len || end < 0) {
         end = len;
      }
      for (int i = start; i < end; i++) {
         if (str.charAt(i) == searchChar) {
            return i;
         }
      }
      return -1;
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找字符串,忽略大小写<br>
    *
    * <pre>
    * StringUtil.indexOfIgnoreCase(null, *, *)          = -1
    * StringUtil.indexOfIgnoreCase(*, null, *)          = -1
    * StringUtil.indexOfIgnoreCase("", "", 0)           = 0
    * StringUtil.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    * StringUtil.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    * StringUtil.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    * StringUtil.indexOfIgnoreCase("abc", "", 9)        = -1
    * </pre>
    *
    * @param str       å­—符串
    * @param searchStr éœ€è¦æŸ¥æ‰¾ä½ç½®çš„字符串
    * @return ä½ç½®
    * @since 3.2.1
    */
   public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
      return indexOfIgnoreCase(str, searchStr, 0);
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找字符串
    *
    * <pre>
    * StringUtil.indexOfIgnoreCase(null, *, *)          = -1
    * StringUtil.indexOfIgnoreCase(*, null, *)          = -1
    * StringUtil.indexOfIgnoreCase("", "", 0)           = 0
    * StringUtil.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    * StringUtil.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    * StringUtil.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    * StringUtil.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    * StringUtil.indexOfIgnoreCase("abc", "", 9)        = -1
    * </pre>
    *
    * @param str       å­—符串
    * @param searchStr éœ€è¦æŸ¥æ‰¾ä½ç½®çš„字符串
    * @param fromIndex èµ·å§‹ä½ç½®
    * @return ä½ç½®
    * @since 3.2.1
    */
   public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int fromIndex) {
      return indexOf(str, searchStr, fromIndex, true);
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…反向查找字符串
    *
    * @param str        å­—符串
    * @param searchStr  éœ€è¦æŸ¥æ‰¾ä½ç½®çš„字符串
    * @param fromIndex  èµ·å§‹ä½ç½®
    * @param ignoreCase æ˜¯å¦å¿½ç•¥å¤§å°å†™
    * @return ä½ç½®
    * @since 3.2.1
    */
   public static int indexOf(final CharSequence str, CharSequence searchStr, int fromIndex, boolean ignoreCase) {
      if (str == null || searchStr == null) {
         return INDEX_NOT_FOUND;
      }
      if (fromIndex < 0) {
         fromIndex = 0;
      }
      final int endLimit = str.length() - searchStr.length() + 1;
      if (fromIndex > endLimit) {
         return INDEX_NOT_FOUND;
      }
      if (searchStr.length() == 0) {
         return fromIndex;
      }
      if (false == ignoreCase) {
         // ä¸å¿½ç•¥å¤§å°å†™è°ƒç”¨JDK方法
         return str.toString().indexOf(searchStr.toString(), fromIndex);
      }
      for (int i = fromIndex; i < endLimit; i++) {
         if (isSubEquals(str, i, searchStr, 0, searchStr.length(), true)) {
            return i;
         }
      }
      return INDEX_NOT_FOUND;
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找字符串,忽略大小写<br>
    *
    * @param str       å­—符串
    * @param searchStr éœ€è¦æŸ¥æ‰¾ä½ç½®çš„字符串
    * @return ä½ç½®
    * @since 3.2.1
    */
   public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
      return lastIndexOfIgnoreCase(str, searchStr, str.length());
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找字符串,忽略大小写<br>
    *
    * @param str       å­—符串
    * @param searchStr éœ€è¦æŸ¥æ‰¾ä½ç½®çš„字符串
    * @param fromIndex èµ·å§‹ä½ç½®ï¼Œä»ŽåŽå¾€å‰è®¡æ•°
    * @return ä½ç½®
    * @since 3.2.1
    */
   public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int fromIndex) {
      return lastIndexOf(str, searchStr, fromIndex, true);
   }
   /**
    * æŒ‡å®šèŒƒå›´å†…查找字符串<br>
    *
    * @param str        å­—符串
    * @param searchStr  éœ€è¦æŸ¥æ‰¾ä½ç½®çš„字符串
    * @param fromIndex  èµ·å§‹ä½ç½®ï¼Œä»ŽåŽå¾€å‰è®¡æ•°
    * @param ignoreCase æ˜¯å¦å¿½ç•¥å¤§å°å†™
    * @return ä½ç½®
    * @since 3.2.1
    */
   public static int lastIndexOf(final CharSequence str, final CharSequence searchStr, int fromIndex, boolean ignoreCase) {
      if (str == null || searchStr == null) {
         return INDEX_NOT_FOUND;
      }
      if (fromIndex < 0) {
         fromIndex = 0;
      }
      fromIndex = Math.min(fromIndex, str.length());
      if (searchStr.length() == 0) {
         return fromIndex;
      }
      if (false == ignoreCase) {
         // ä¸å¿½ç•¥å¤§å°å†™è°ƒç”¨JDK方法
         return str.toString().lastIndexOf(searchStr.toString(), fromIndex);
      }
      for (int i = fromIndex; i > 0; i--) {
         if (isSubEquals(str, i, searchStr, 0, searchStr.length(), true)) {
            return i;
         }
      }
      return INDEX_NOT_FOUND;
   }
   /**
    * è¿”回字符串 searchStr åœ¨å­—符串 str ä¸­ç¬¬ ordinal æ¬¡å‡ºçŽ°çš„ä½ç½®ã€‚<br>
    * æ­¤æ–¹æ³•来自:Apache-Commons-Lang
    * <p>
    * æ —子(*代表任意字符):
    *
    * <pre>
    * StringUtil.ordinalIndexOf(null, *, *)          = -1
    * StringUtil.ordinalIndexOf(*, null, *)          = -1
    * StringUtil.ordinalIndexOf("", "", *)           = 0
    * StringUtil.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    * StringUtil.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    * StringUtil.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    * StringUtil.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    * StringUtil.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    * StringUtil.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    * StringUtil.ordinalIndexOf("aabaabaa", "", 1)   = 0
    * StringUtil.ordinalIndexOf("aabaabaa", "", 2)   = 0
    * </pre>
    *
    * @param str       è¢«æ£€æŸ¥çš„字符串,可以为null
    * @param searchStr è¢«æŸ¥æ‰¾çš„字符串,可以为null
    * @param ordinal   ç¬¬å‡ æ¬¡å‡ºçŽ°çš„ä½ç½®
    * @return æŸ¥æ‰¾åˆ°çš„位置
    * @since 3.2.3
    */
   public static int ordinalIndexOf(String str, String searchStr, int ordinal) {
      if (str == null || searchStr == null || ordinal <= 0) {
         return INDEX_NOT_FOUND;
      }
      if (searchStr.length() == 0) {
         return 0;
      }
      int found = 0;
      int index = INDEX_NOT_FOUND;
      do {
         index = str.indexOf(searchStr, index + 1);
         if (index < 0) {
            return index;
         }
         found++;
      } while (found < ordinal);
      return index;
   }
   /**
    * æˆªå–两个字符串的不同部分(长度一致),判断截取的子串是否相同<br>
    * ä»»æ„ä¸€ä¸ªå­—符串为null返回false
    *
    * @param str1       ç¬¬ä¸€ä¸ªå­—符串
    * @param start1     ç¬¬ä¸€ä¸ªå­—符串开始的位置
    * @param str2       ç¬¬äºŒä¸ªå­—符串
    * @param start2     ç¬¬äºŒä¸ªå­—符串开始的位置
    * @param length     æˆªå–长度
    * @param ignoreCase æ˜¯å¦å¿½ç•¥å¤§å°å†™
    * @return å­ä¸²æ˜¯å¦ç›¸åŒ
    * @since 3.2.1
    */
   public static boolean isSubEquals(CharSequence str1, int start1, CharSequence str2, int start2, int length, boolean ignoreCase) {
      if (null == str1 || null == str2) {
         return false;
      }
      return str1.toString().regionMatches(ignoreCase, start1, str2.toString(), start2, length);
   }
   /**
    * æ¯”较两个字符串(大小写敏感)。
    *
    * <pre>
    * equalsIgnoreCase(null, null)   = true
    * equalsIgnoreCase(null, &quot;abc&quot;)  = false
    * equalsIgnoreCase(&quot;abc&quot;, null)  = false
    * equalsIgnoreCase(&quot;abc&quot;, &quot;abc&quot;) = true
    * equalsIgnoreCase(&quot;abc&quot;, &quot;ABC&quot;) = true
    * </pre>
    *
    * @param str1 è¦æ¯”较的字符串1
    * @param str2 è¦æ¯”较的字符串2
    * @return å¦‚果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code>
    */
   public static boolean equals(CharSequence str1, CharSequence str2) {
      return equals(str1, str2, false);
   }
   /**
    * æ¯”较两个字符串(大小写不敏感)。
    *
    * <pre>
    * equalsIgnoreCase(null, null)   = true
    * equalsIgnoreCase(null, &quot;abc&quot;)  = false
    * equalsIgnoreCase(&quot;abc&quot;, null)  = false
    * equalsIgnoreCase(&quot;abc&quot;, &quot;abc&quot;) = true
    * equalsIgnoreCase(&quot;abc&quot;, &quot;ABC&quot;) = true
    * </pre>
    *
    * @param str1 è¦æ¯”较的字符串1
    * @param str2 è¦æ¯”较的字符串2
    * @return å¦‚果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code>
    */
   public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
      return equals(str1, str2, true);
   }
   /**
    * æ¯”较两个字符串是否相等。
    *
    * @param str1       è¦æ¯”较的字符串1
    * @param str2       è¦æ¯”较的字符串2
    * @param ignoreCase æ˜¯å¦å¿½ç•¥å¤§å°å†™
    * @return å¦‚果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code>
    * @since 3.2.0
    */
   public static boolean equals(CharSequence str1, CharSequence str2, boolean ignoreCase) {
      if (null == str1) {
         // åªæœ‰ä¸¤ä¸ªéƒ½ä¸ºnull才判断相等
         return str2 == null;
      }
      if (null == str2) {
         // å­—符串2空,字符串1非空,直接false
         return false;
      }
      if (ignoreCase) {
         return str1.toString().equalsIgnoreCase(str2.toString());
      } else {
         return str1.equals(str2);
      }
   }
   /**
    * åˆ›å»ºStringBuilder对象
    *
    * @return {String}Builder对象
    */
   public static StringBuilder builder() {
      return new StringBuilder();
   }
   /**
    * åˆ›å»ºStringBuilder对象
    *
    * @param capacity åˆå§‹å¤§å°
    * @return {String}Builder对象
    */
   public static StringBuilder builder(int capacity) {
      return new StringBuilder(capacity);
   }
   /**
    * åˆ›å»ºStringBuilder对象
    *
    * @param strs åˆå§‹å­—符串列表
    * @return {String}Builder对象
    */
   public static StringBuilder builder(CharSequence... strs) {
      final StringBuilder sb = new StringBuilder();
      for (CharSequence str : strs) {
         sb.append(str);
      }
      return sb;
   }
   /**
    * åˆ›å»ºStringBuilder对象
    *
    * @param sb   åˆå§‹StringBuilder
    * @param strs åˆå§‹å­—符串列表
    * @return {String}Builder对象
    */
   public static StringBuilder appendBuilder(StringBuilder sb, CharSequence... strs) {
      for (CharSequence str : strs) {
         sb.append(str);
      }
      return sb;
   }
   /**
    * èŽ·å¾—StringReader
    *
    * @param str å­—符串
    * @return {String}Reader
    */
   public static StringReader getReader(CharSequence str) {
      if (null == str) {
         return null;
      }
      return new StringReader(str.toString());
   }
   /**
    * èŽ·å¾—StringWriter
    *
    * @return {String}Writer
    */
   public static StringWriter getWriter() {
      return new StringWriter();
   }
   /**
    * ç»Ÿè®¡æŒ‡å®šå†…容中包含指定字符串的数量<br>
    * å‚数为 {@code null} æˆ–者 "" è¿”回 {@code 0}.
    *
    * <pre>
    * StringUtil.count(null, *)       = 0
    * StringUtil.count("", *)         = 0
    * StringUtil.count("abba", null)  = 0
    * StringUtil.count("abba", "")    = 0
    * StringUtil.count("abba", "a")   = 2
    * StringUtil.count("abba", "ab")  = 1
    * StringUtil.count("abba", "xxx") = 0
    * </pre>
    *
    * @param content      è¢«æŸ¥æ‰¾çš„字符串
    * @param strForSearch éœ€è¦æŸ¥æ‰¾çš„字符串
    * @return æŸ¥æ‰¾åˆ°çš„个数
    */
   public static int count(CharSequence content, CharSequence strForSearch) {
      if (Func.hasEmpty(content, strForSearch) || strForSearch.length() > content.length()) {
         return 0;
      }
      int count = 0;
      int idx = 0;
      final String content2 = content.toString();
      final String strForSearch2 = strForSearch.toString();
      while ((idx = content2.indexOf(strForSearch2, idx)) > -1) {
         count++;
         idx += strForSearch.length();
      }
      return count;
   }
   /**
    * ç»Ÿè®¡æŒ‡å®šå†…容中包含指定字符的数量
    *
    * @param content       å†…容
    * @param charForSearch è¢«ç»Ÿè®¡çš„字符
    * @return åŒ…含数量
    */
   public static int count(CharSequence content, char charForSearch) {
      int count = 0;
      if (isEmpty(content)) {
         return 0;
      }
      int contentLength = content.length();
      for (int i = 0; i < contentLength; i++) {
         if (charForSearch == content.charAt(i)) {
            count++;
         }
      }
      return count;
   }
   /**
    * ä¸‹åˆ’线转驼峰
    *
    * @param para å­—符串
    * @return {String}
    */
   public static String underlineToHump(String para) {
      if (isBlank(para)) {
         return StringPool.EMPTY;
      }
      StringBuilder result = new StringBuilder();
      String[] a = para.split("_");
      for (String s : a) {
         if (result.length() == 0) {
            result.append(s.toLowerCase());
         } else {
            result.append(s.substring(0, 1).toUpperCase());
            result.append(s.substring(1).toLowerCase());
         }
      }
      return result.toString();
   }
   /**
    * é©¼å³°è½¬ä¸‹åˆ’线
    *
    * @param para å­—符串
    * @return {String}
    */
   public static String humpToUnderline(String para) {
      if (isBlank(para)) {
         return StringPool.EMPTY;
      }
      para = firstCharToLower(para);
      StringBuilder sb = new StringBuilder(para);
      int temp = 0;
      for (int i = 0; i < para.length(); i++) {
         if (Character.isUpperCase(para.charAt(i))) {
            sb.insert(i + temp, "_");
            temp += 1;
         }
      }
      return sb.toString().toLowerCase();
   }
   /**
    * æ¨ªçº¿è½¬é©¼å³°
    *
    * @param para å­—符串
    * @return {String}
    */
   public static String lineToHump(String para) {
      if (isBlank(para)) {
         return StringPool.EMPTY;
      }
      StringBuilder result = new StringBuilder();
      String[] a = para.split("-");
      for (String s : a) {
         if (result.length() == 0) {
            result.append(s.toLowerCase());
         } else {
            result.append(s.substring(0, 1).toUpperCase());
            result.append(s.substring(1).toLowerCase());
         }
      }
      return result.toString();
   }
   /**
    * é©¼å³°è½¬æ¨ªçº¿
    *
    * @param para å­—符串
    * @return {String}
    */
   public static String humpToLine(String para) {
      if (isBlank(para)) {
         return StringPool.EMPTY;
      }
      para = firstCharToLower(para);
      StringBuilder sb = new StringBuilder(para);
      int temp = 0;
      for (int i = 0; i < para.length(); i++) {
         if (Character.isUpperCase(para.charAt(i))) {
            sb.insert(i + temp, "-");
            temp += 1;
         }
      }
      return sb.toString().toLowerCase();
   }
}