| package com.ruoyi.study.utils; | 
|   | 
| import java.io.StringReader; | 
| import java.io.StringWriter; | 
| import java.io.UnsupportedEncodingException; | 
| import java.nio.ByteBuffer; | 
| import java.nio.charset.Charset; | 
| import java.util.ArrayList; | 
| import java.util.Arrays; | 
| import java.util.List; | 
| import java.util.Map; | 
| import java.util.Map.Entry; | 
|   | 
| /** | 
|  * 字符串工具类 | 
|  *  | 
|  * @author xiaoleilu | 
|  * | 
|  */ | 
| public class StrKit { | 
|   | 
|     public static final String SPACE = " "; | 
|     public static final String DOT = "."; | 
|     public static final String SLASH = "/"; | 
|     public static final String BACKSLASH = "\\"; | 
|     public static final String EMPTY = ""; | 
|     public static final String CRLF = "\r\n"; | 
|     public static final String NEWLINE = "\n"; | 
|     public static final String UNDERLINE = "_"; | 
|     public static final String COMMA = ","; | 
|   | 
|     public static final String HTML_NBSP = " "; | 
|     public static final String HTML_AMP = "&"; | 
|     public static final String HTML_QUOTE = """; | 
|     public static final String HTML_LT = "<"; | 
|     public static final String HTML_GT = ">"; | 
|   | 
|     public static final String EMPTY_JSON = "{}"; | 
|   | 
|   | 
|     /** | 
|      * 首字母变小写 | 
|      */ | 
|     public static String firstCharToLowerCase(String str) { | 
|         char firstChar = str.charAt(0); | 
|         if (firstChar >= 'A' && firstChar <= 'Z') { | 
|             char[] arr = str.toCharArray(); | 
|             arr[0] += ('a' - 'A'); | 
|             return new String(arr); | 
|         } | 
|         return str; | 
|     } | 
|      | 
|     /** | 
|      * 首字母变大写 | 
|      */ | 
|     public static String firstCharToUpperCase(String str) { | 
|         char firstChar = str.charAt(0); | 
|         if (firstChar >= 'a' && firstChar <= 'z') { | 
|             char[] arr = str.toCharArray(); | 
|             arr[0] -= ('a' - 'A'); | 
|             return new String(arr); | 
|         } | 
|         return str; | 
|     } | 
|   | 
|     // ------------------------------------------------------------------------ Blank | 
|     /** | 
|      * 字符串是否为空白 空白的定义如下: <br> | 
|      * 1、为null <br> | 
|      * 2、为不可见字符(如空格)<br> | 
|      * 3、""<br> | 
|      *  | 
|      * @param str 被检测的字符串 | 
|      * @return 是否为空 | 
|      */ | 
|     public static boolean isBlank(String str) { | 
|         int length; | 
|         if ((str == null) || ((length = str.length()) == 0)) { | 
|             return true; | 
|         } | 
|         for (int i = 0; i < length; i++) { | 
|             // 只要有一个非空字符即为非空字符串 | 
|             if (false == Character.isWhitespace(str.charAt(i))) { | 
|                 return false; | 
|             } | 
|         } | 
|         return true; | 
|     } | 
|   | 
|     /** | 
|      * 字符串是否为非空白 空白的定义如下: <br> | 
|      * 1、不为null <br> | 
|      * 2、不为不可见字符(如空格)<br> | 
|      * 3、不为""<br> | 
|      *  | 
|      * @param str 被检测的字符串 | 
|      * @return 是否为非空 | 
|      */ | 
|     public static boolean notBlank(String str) { | 
|         return false == isBlank(str); | 
|     } | 
|   | 
|     /** | 
|      * 是否包含空字符串 | 
|      *  | 
|      * @param strs 字符串列表 | 
|      * @return 是否包含空字符串 | 
|      */ | 
|     public static boolean hasBlank(String... strs) { | 
|         if (CollectionKit.isEmpty(strs)) { | 
|             return true; | 
|         } | 
|         for (String str : strs) { | 
|             if (isBlank(str)) { | 
|                 return true; | 
|             } | 
|         } | 
|         return false; | 
|     } | 
|   | 
|     /** | 
|      * 给定所有字符串是否为空白 | 
|      *  | 
|      * @param strs 字符串 | 
|      * @return 所有字符串是否为空白 | 
|      */ | 
|     public static boolean isAllBlank(String... strs) { | 
|         if (CollectionKit.isEmpty(strs)) { | 
|             return true; | 
|         } | 
|         for (String str : strs) { | 
|             if (notBlank(str)) { | 
|                 return false; | 
|             } | 
|         } | 
|         return true; | 
|     } | 
|   | 
|     // ------------------------------------------------------------------------ Empty | 
|     /** | 
|      * 字符串是否为空,空的定义如下 1、为null <br> | 
|      * 2、为""<br> | 
|      *  | 
|      * @param str 被检测的字符串 | 
|      * @return 是否为空 | 
|      */ | 
|     public static boolean isEmpty(String str) { | 
|         return str == null || str.length() == 0; | 
|     } | 
|   | 
|     /** | 
|      * 字符串是否为非空白 空白的定义如下: <br> | 
|      * 1、不为null <br> | 
|      * 2、不为""<br> | 
|      *  | 
|      * @param str 被检测的字符串 | 
|      * @return 是否为非空 | 
|      */ | 
|     public static boolean isNotEmpty(String str) { | 
|         return false == isEmpty(str); | 
|     } | 
|   | 
|     /** | 
|      * 当给定字符串为null时,转换为Empty | 
|      *  | 
|      * @param str 被转换的字符串 | 
|      * @return 转换后的字符串 | 
|      */ | 
|     public static String nullToEmpty(String str) { | 
|         return nullToDefault(str, EMPTY); | 
|     } | 
|   | 
|     /** | 
|      * 如果字符串是<code>null</code>,则返回指定默认字符串,否则返回字符串本身。 | 
|      *  | 
|      * <pre> | 
|      * nullToDefault(null, "default")  = "default" | 
|      * nullToDefault("", "default")    = "" | 
|      * nullToDefault("  ", "default")  = "  " | 
|      * nullToDefault("bat", "default") = "bat" | 
|      * </pre> | 
|      *  | 
|      * @param str 要转换的字符串 | 
|      * @param defaultStr 默认字符串 | 
|      *  | 
|      * @return 字符串本身或指定的默认字符串 | 
|      */ | 
|     public static String nullToDefault(String str, String defaultStr) { | 
|         return (str == null) ? defaultStr : str; | 
|     } | 
|   | 
|     /** | 
|      * 当给定字符串为空字符串时,转换为<code>null</code> | 
|      *  | 
|      * @param str 被转换的字符串 | 
|      * @return 转换后的字符串 | 
|      */ | 
|     public static String emptyToNull(String str) { | 
|         return isEmpty(str) ? null : str; | 
|     } | 
|   | 
|     /** | 
|      * 是否包含空字符串 | 
|      *  | 
|      * @param strs 字符串列表 | 
|      * @return 是否包含空字符串 | 
|      */ | 
|     public static boolean hasEmpty(String... strs) { | 
|         if (CollectionKit.isEmpty(strs)) { | 
|             return true; | 
|         } | 
|   | 
|         for (String str : strs) { | 
|             if (isEmpty(str)) { | 
|                 return true; | 
|             } | 
|         } | 
|         return false; | 
|     } | 
|   | 
|     /** | 
|      * 是否全部为空字符串 | 
|      *  | 
|      * @param strs 字符串列表 | 
|      * @return 是否全部为空字符串 | 
|      */ | 
|     public static boolean isAllEmpty(String... strs) { | 
|         if (CollectionKit.isEmpty(strs)) { | 
|             return true; | 
|         } | 
|   | 
|         for (String str : strs) { | 
|             if (isNotEmpty(str)) { | 
|                 return false; | 
|             } | 
|         } | 
|         return true; | 
|     } | 
|   | 
|     // ------------------------------------------------------------------------ Trim | 
|     /** | 
|      * 除去字符串头尾部的空白,如果字符串是<code>null</code>,依然返回<code>null</code>。 | 
|      *  | 
|      * <p> | 
|      * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 | 
|      *  | 
|      * <pre> | 
|      * trim(null)          = null | 
|      * trim("")            = "" | 
|      * trim("     ")       = "" | 
|      * trim("abc")         = "abc" | 
|      * trim("    abc    ") = "abc" | 
|      * </pre> | 
|      *  | 
|      * </p> | 
|      *  | 
|      * @param str 要处理的字符串 | 
|      *  | 
|      * @return 除去空白的字符串,如果原字串为<code>null</code>,则返回<code>null</code> | 
|      */ | 
|     public static String trim(String str) { | 
|         return (null == str) ? null : trim(str, 0); | 
|     } | 
|   | 
|     /** | 
|      * 给定字符串数组全部做去首尾空格 | 
|      *  | 
|      * @param strs 字符串数组 | 
|      */ | 
|     public static void trim(String[] strs) { | 
|         if (null == strs) { | 
|             return; | 
|         } | 
|         String str; | 
|         for (int i = 0; i < strs.length; i++) { | 
|             str = strs[i]; | 
|             if (null != str) { | 
|                 strs[i] = str.trim(); | 
|             } | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 除去字符串头部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。 | 
|      *  | 
|      * <p> | 
|      * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 | 
|      *  | 
|      * <pre> | 
|      * trimStart(null)         = null | 
|      * trimStart("")           = "" | 
|      * trimStart("abc")        = "abc" | 
|      * trimStart("  abc")      = "abc" | 
|      * trimStart("abc  ")      = "abc  " | 
|      * trimStart(" abc ")      = "abc " | 
|      * </pre> | 
|      *  | 
|      * </p> | 
|      *  | 
|      * @param str 要处理的字符串 | 
|      *  | 
|      * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code> | 
|      */ | 
|     public static String trimStart(String str) { | 
|         return trim(str, -1); | 
|     } | 
|   | 
|     /** | 
|      * 除去字符串尾部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。 | 
|      *  | 
|      * <p> | 
|      * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 | 
|      *  | 
|      * <pre> | 
|      * trimEnd(null)       = null | 
|      * trimEnd("")         = "" | 
|      * trimEnd("abc")      = "abc" | 
|      * trimEnd("  abc")    = "  abc" | 
|      * trimEnd("abc  ")    = "abc" | 
|      * trimEnd(" abc ")    = " abc" | 
|      * </pre> | 
|      *  | 
|      * </p> | 
|      *  | 
|      * @param str 要处理的字符串 | 
|      *  | 
|      * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code> | 
|      */ | 
|     public static String trimEnd(String str) { | 
|         return trim(str, 1); | 
|     } | 
|   | 
|     /** | 
|      * 除去字符串头尾部的空白符,如果字符串是<code>null</code>,依然返回<code>null</code>。 | 
|      *  | 
|      * @param str 要处理的字符串 | 
|      * @param mode <code>-1</code>表示trimStart,<code>0</code>表示trim全部, <code>1</code>表示trimEnd | 
|      *  | 
|      * @return 除去指定字符后的的字符串,如果原字串为<code>null</code>,则返回<code>null</code> | 
|      */ | 
|     public static String trim(String str, int mode) { | 
|         if (str == null) { | 
|             return null; | 
|         } | 
|   | 
|         int length = str.length(); | 
|         int start = 0; | 
|         int end = length; | 
|   | 
|         // 扫描字符串头部 | 
|         if (mode <= 0) { | 
|             while ((start < end) && (Character.isWhitespace(str.charAt(start)))) { | 
|                 start++; | 
|             } | 
|         } | 
|   | 
|         // 扫描字符串尾部 | 
|         if (mode >= 0) { | 
|             while ((start < end) && (Character.isWhitespace(str.charAt(end - 1)))) { | 
|                 end--; | 
|             } | 
|         } | 
|   | 
|         if ((start > 0) || (end < length)) { | 
|             return str.substring(start, end); | 
|         } | 
|   | 
|         return str; | 
|     } | 
|      | 
|     /** | 
|      * 是否以指定字符串开头 | 
|      * @param str 被监测字符串 | 
|      * @param prefix 开头字符串 | 
|      * @param isIgnoreCase 是否忽略大小写 | 
|      * @return 是否以指定字符串开头 | 
|      */ | 
|     public static boolean startWith(String str, String prefix, boolean isIgnoreCase){ | 
|         if(isIgnoreCase){ | 
|             return str.toLowerCase().startsWith(prefix.toLowerCase()); | 
|         }else{ | 
|             return str.startsWith(prefix); | 
|         } | 
|     } | 
|      | 
|     /** | 
|      * 是否以指定字符串结尾 | 
|      * @param str 被监测字符串 | 
|      * @param suffix 结尾字符串 | 
|      * @param isIgnoreCase 是否忽略大小写 | 
|      * @return 是否以指定字符串结尾 | 
|      */ | 
|     public static boolean endWith(String str, String suffix, boolean isIgnoreCase){ | 
|         if(isIgnoreCase){ | 
|             return str.toLowerCase().endsWith(suffix.toLowerCase()); | 
|         }else{ | 
|             return str.endsWith(suffix); | 
|         } | 
|     } | 
|      | 
|     /** | 
|      * 是否包含特定字符,忽略大小写,如果给定两个参数都为<code>null</code>,返回true | 
|      * @param str 被检测字符串 | 
|      * @param testStr 被测试是否包含的字符串 | 
|      * @return 是否包含 | 
|      */ | 
|     public static boolean containsIgnoreCase(String str, String testStr){ | 
|         if(null == str){ | 
|             //如果被监测字符串和  | 
|             return null == testStr; | 
|         } | 
|         return str.toLowerCase().contains(testStr.toLowerCase()); | 
|     } | 
|   | 
|     /** | 
|      * 获得set或get方法对应的标准属性名<br/> | 
|      * 例如:setName 返回 name | 
|      *  | 
|      * @param getOrSetMethodName | 
|      * @return 如果是set或get方法名,返回field, 否则null | 
|      */ | 
|     public static String getGeneralField(String getOrSetMethodName) { | 
|         if (getOrSetMethodName.startsWith("get") || getOrSetMethodName.startsWith("set")) { | 
|             return cutPreAndLowerFirst(getOrSetMethodName, 3); | 
|         } | 
|         return null; | 
|     } | 
|   | 
|     /** | 
|      * 生成set方法名<br/> | 
|      * 例如:name 返回 setName | 
|      *  | 
|      * @param fieldName 属性名 | 
|      * @return setXxx | 
|      */ | 
|     public static String genSetter(String fieldName) { | 
|         return upperFirstAndAddPre(fieldName, "set"); | 
|     } | 
|   | 
|     /** | 
|      * 生成get方法名 | 
|      *  | 
|      * @param fieldName 属性名 | 
|      * @return getXxx | 
|      */ | 
|     public static String genGetter(String fieldName) { | 
|         return upperFirstAndAddPre(fieldName, "get"); | 
|     } | 
|   | 
|     /** | 
|      * 去掉首部指定长度的字符串并将剩余字符串首字母小写<br/> | 
|      * 例如:str=setName, preLength=3 -> return name | 
|      *  | 
|      * @param str 被处理的字符串 | 
|      * @param preLength 去掉的长度 | 
|      * @return 处理后的字符串,不符合规范返回null | 
|      */ | 
|     public static String cutPreAndLowerFirst(String str, int preLength) { | 
|         if (str == null) { | 
|             return null; | 
|         } | 
|         if (str.length() > preLength) { | 
|             char first = Character.toLowerCase(str.charAt(preLength)); | 
|             if (str.length() > preLength + 1) { | 
|                 return first + str.substring(preLength + 1); | 
|             } | 
|             return String.valueOf(first); | 
|         } | 
|         return null; | 
|     } | 
|   | 
|     /** | 
|      * 原字符串首字母大写并在其首部添加指定字符串 例如:str=name, preString=get -> return getName | 
|      *  | 
|      * @param str 被处理的字符串 | 
|      * @param preString 添加的首部 | 
|      * @return 处理后的字符串 | 
|      */ | 
|     public static String upperFirstAndAddPre(String str, String preString) { | 
|         if (str == null || preString == null) { | 
|             return null; | 
|         } | 
|         return preString + upperFirst(str); | 
|     } | 
|   | 
|     /** | 
|      * 大写首字母<br> | 
|      * 例如:str = name, return Name | 
|      *  | 
|      * @param str 字符串 | 
|      * @return 字符串 | 
|      */ | 
|     public static String upperFirst(String str) { | 
|         return Character.toUpperCase(str.charAt(0)) + str.substring(1); | 
|     } | 
|   | 
|     /** | 
|      * 小写首字母<br> | 
|      * 例如:str = Name, return name | 
|      *  | 
|      * @param str 字符串 | 
|      * @return 字符串 | 
|      */ | 
|     public static String lowerFirst(String str) { | 
|         if(isBlank(str)){ | 
|             return str; | 
|         } | 
|         return Character.toLowerCase(str.charAt(0)) + str.substring(1); | 
|     } | 
|   | 
|     /** | 
|      * 去掉指定前缀 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param prefix 前缀 | 
|      * @return 切掉后的字符串,若前缀不是 preffix, 返回原字符串 | 
|      */ | 
|     public static String removePrefix(String str, String prefix) { | 
|         if(isEmpty(str) || isEmpty(prefix)){ | 
|             return str; | 
|         } | 
|          | 
|         if (str.startsWith(prefix)) { | 
|             return str.substring(prefix.length()); | 
|         } | 
|         return str; | 
|     } | 
|   | 
|     /** | 
|      * 忽略大小写去掉指定前缀 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param prefix 前缀 | 
|      * @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串 | 
|      */ | 
|     public static String removePrefixIgnoreCase(String str, String prefix) { | 
|         if(isEmpty(str) || isEmpty(prefix)){ | 
|             return str; | 
|         } | 
|          | 
|         if (str.toLowerCase().startsWith(prefix.toLowerCase())) { | 
|             return str.substring(prefix.length()); | 
|         } | 
|         return str; | 
|     } | 
|   | 
|     /** | 
|      * 去掉指定后缀 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param suffix 后缀 | 
|      * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串 | 
|      */ | 
|     public static String removeSuffix(String str, String suffix) { | 
|         if(isEmpty(str) || isEmpty(suffix)){ | 
|             return str; | 
|         } | 
|          | 
|         if (str.endsWith(suffix)) { | 
|             return str.substring(0, str.length() - suffix.length()); | 
|         } | 
|         return str; | 
|     } | 
|      | 
|     /** | 
|      * 获得字符串对应byte数组 | 
|      * @param str 字符串 | 
|      * @param charset 编码,如果为<code>null</code>使用系统默认编码 | 
|      * @return bytes | 
|      */ | 
|     public static byte[] getBytes(String str, Charset charset){ | 
|         if(null == str){ | 
|             return null; | 
|         } | 
|         return null == charset ? str.getBytes() : str.getBytes(charset); | 
|     } | 
|   | 
|     /** | 
|      * 忽略大小写去掉指定后缀 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param suffix 后缀 | 
|      * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串 | 
|      */ | 
|     public static String removeSuffixIgnoreCase(String str, String suffix) { | 
|         if(isEmpty(str) || isEmpty(suffix)){ | 
|             return str; | 
|         } | 
|          | 
|         if (str.toLowerCase().endsWith(suffix.toLowerCase())) { | 
|             return str.substring(0, str.length() - suffix.length()); | 
|         } | 
|         return str; | 
|     } | 
|      | 
|     /** | 
|      * 如果给定字符串不是以prefix开头的,在开头补充 prefix | 
|      * @param str 字符串 | 
|      * @param prefix 前缀 | 
|      * @return 补充后的字符串 | 
|      */ | 
|     public static String addPrefixIfNot(String str, String prefix){ | 
|         if(isEmpty(str) || isEmpty(prefix)){ | 
|             return str; | 
|         } | 
|         if(false == str.startsWith(prefix)){ | 
|             str = prefix + str; | 
|         } | 
|         return str; | 
|     } | 
|      | 
|     /** | 
|      * 如果给定字符串不是以suffix结尾的,在尾部补充 suffix | 
|      * @param str 字符串 | 
|      * @param suffix 后缀 | 
|      * @return 补充后的字符串 | 
|      */ | 
|     public static String addSuffixIfNot(String str, String suffix){ | 
|         if(isEmpty(str) || isEmpty(suffix)){ | 
|             return str; | 
|         } | 
|         if(false == str.endsWith(suffix)){ | 
|             str += suffix; | 
|         } | 
|         return str; | 
|     } | 
|   | 
|     /** | 
|      * 清理空白字符 | 
|      *  | 
|      * @param str 被清理的字符串 | 
|      * @return 清理后的字符串 | 
|      */ | 
|     public static String cleanBlank(String str) { | 
|         if (str == null) { | 
|             return null; | 
|         } | 
|   | 
|         return str.replaceAll("\\s*", EMPTY); | 
|     } | 
|   | 
|     /** | 
|      * 切分字符串<br> | 
|      * a#b#c -> [a,b,c] <br> | 
|      * a##b#c -> [a,"",b,c] | 
|      *  | 
|      * @param str 被切分的字符串 | 
|      * @param separator 分隔符字符 | 
|      * @return 切分后的集合 | 
|      */ | 
|     public static List<String> split(String str, char separator) { | 
|         return split(str, separator, 0); | 
|     } | 
|   | 
|     /** | 
|      * 切分字符串 | 
|      *  | 
|      * @param str 被切分的字符串 | 
|      * @param separator 分隔符字符 | 
|      * @param limit 限制分片数 | 
|      * @return 切分后的集合 | 
|      */ | 
|     public static List<String> split(String str, char separator, int limit) { | 
|         if (str == null) { | 
|             return null; | 
|         } | 
|         List<String> list = new ArrayList<String>(limit == 0 ? 16 : limit); | 
|         if (limit == 1) { | 
|             list.add(str); | 
|             return list; | 
|         } | 
|   | 
|         boolean isNotEnd = true; // 未结束切分的标志 | 
|         int strLen = str.length(); | 
|         StringBuilder sb = new StringBuilder(strLen); | 
|         for (int i = 0; i < strLen; i++) { | 
|             char c = str.charAt(i); | 
|             if (isNotEnd && c == separator) { | 
|                 list.add(sb.toString()); | 
|                 // 清空StringBuilder | 
|                 sb.delete(0, sb.length()); | 
|   | 
|                 // 当达到切分上限-1的量时,将所剩字符全部作为最后一个串 | 
|                 if (limit != 0 && list.size() == limit - 1) { | 
|                     isNotEnd = false; | 
|                 } | 
|             } else { | 
|                 sb.append(c); | 
|             } | 
|         } | 
|         list.add(sb.toString());// 加入尾串 | 
|         return list; | 
|     } | 
|   | 
|     /** | 
|      * 切分字符串<br> | 
|      * from jodd | 
|      *  | 
|      * @param str 被切分的字符串 | 
|      * @param delimiter 分隔符 | 
|      * @return 字符串 | 
|      */ | 
|     public static String[] split(String str, String delimiter) { | 
|         if (str == null) { | 
|             return null; | 
|         } | 
|         if (str.trim().length() == 0) { | 
|             return new String[] { str }; | 
|         } | 
|   | 
|         int dellen = delimiter.length(); // del length | 
|         int maxparts = (str.length() / dellen) + 2; // one more for the last | 
|         int[] positions = new int[maxparts]; | 
|   | 
|         int i, j = 0; | 
|         int count = 0; | 
|         positions[0] = -dellen; | 
|         while ((i = str.indexOf(delimiter, j)) != -1) { | 
|             count++; | 
|             positions[count] = i; | 
|             j = i + dellen; | 
|         } | 
|         count++; | 
|         positions[count] = str.length(); | 
|   | 
|         String[] result = new String[count]; | 
|   | 
|         for (i = 0; i < count; i++) { | 
|             result[i] = str.substring(positions[i] + dellen, positions[i + 1]); | 
|         } | 
|         return result; | 
|     } | 
|   | 
|     /** | 
|      * 改进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 string String | 
|      * @param fromIndex 开始的index(包括) | 
|      * @param toIndex 结束的index(不包括) | 
|      * @return 字串 | 
|      */ | 
|     public static String sub(String string, int fromIndex, int toIndex) { | 
|         int len = string.length(); | 
|         if (fromIndex < 0) { | 
|             fromIndex = len + fromIndex; | 
|             if(fromIndex < 0 ) {  | 
|                 fromIndex = 0; | 
|             } | 
|         } else if(fromIndex >= len) { | 
|             fromIndex = len -1; | 
|         } | 
|         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 EMPTY; | 
|         } | 
|         char[] strArray = string.toCharArray(); | 
|         char[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex); | 
|         return new String(newStrArray); | 
|     } | 
|   | 
|     /** | 
|      * 切割前部分 | 
|      *  | 
|      * @param string 字符串 | 
|      * @param toIndex 切割到的位置(不包括) | 
|      * @return 切割后的字符串 | 
|      */ | 
|     public static String subPre(String string, int toIndex) { | 
|         return sub(string, 0, toIndex); | 
|     } | 
|   | 
|     /** | 
|      * 切割后部分 | 
|      *  | 
|      * @param string 字符串 | 
|      * @param fromIndex 切割开始的位置(包括) | 
|      * @return 切割后的字符串 | 
|      */ | 
|     public static String subSuf(String string, int fromIndex) { | 
|         if (isEmpty(string)) { | 
|             return null; | 
|         } | 
|         return sub(string, fromIndex, string.length()); | 
|     } | 
|   | 
|     /** | 
|      * 给定字符串是否被字符包围 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param prefix 前缀 | 
|      * @param suffix 后缀 | 
|      * @return 是否包围,空串不包围 | 
|      */ | 
|     public static boolean isSurround(String str, String prefix, String suffix) { | 
|         if (StrKit.isBlank(str)) { | 
|             return false; | 
|         } | 
|         if (str.length() < (prefix.length() + suffix.length())) { | 
|             return false; | 
|         } | 
|   | 
|         return str.startsWith(prefix) && str.endsWith(suffix); | 
|     } | 
|   | 
|     /** | 
|      * 给定字符串是否被字符包围 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param prefix 前缀 | 
|      * @param suffix 后缀 | 
|      * @return 是否包围,空串不包围 | 
|      */ | 
|     public static boolean isSurround(String str, char prefix, char suffix) { | 
|         if (StrKit.isBlank(str)) { | 
|             return false; | 
|         } | 
|         if (str.length() < 2) { | 
|             return false; | 
|         } | 
|   | 
|         return str.charAt(0) == prefix && str.charAt(str.length() - 1) == suffix; | 
|     } | 
|   | 
|     /** | 
|      * 重复某个字符 | 
|      *  | 
|      * @param c 被重复的字符 | 
|      * @param count 重复的数目 | 
|      * @return 重复字符字符串 | 
|      */ | 
|     public static String repeat(char c, int count) { | 
|         char[] result = new char[count]; | 
|         for (int i = 0; i < count; i++) { | 
|             result[i] = c; | 
|         } | 
|         return new String(result); | 
|     } | 
|   | 
|     /** | 
|      * 重复某个字符串 | 
|      *  | 
|      * @param str 被重复的字符 | 
|      * @param count 重复的数目 | 
|      * @return 重复字符字符串 | 
|      */ | 
|     public static String repeat(String str, int count) { | 
|   | 
|         // 检查 | 
|         final int len = str.length(); | 
|         final long longSize = (long) len * (long) count; | 
|         final int size = (int) longSize; | 
|         if (size != longSize) { | 
|             throw new ArrayIndexOutOfBoundsException("Required String length is too large: " + longSize); | 
|         } | 
|   | 
|         final char[] array = new char[size]; | 
|         str.getChars(0, len, array, 0); | 
|         int n; | 
|         for (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2 | 
|             System.arraycopy(array, 0, array, n, n); | 
|         } | 
|         System.arraycopy(array, 0, array, n, size - n); | 
|         return new String(array); | 
|     } | 
|   | 
|     /** | 
|      * 比较两个字符串(大小写敏感)。 | 
|      *  | 
|      * <pre> | 
|      * equals(null, null)   = true | 
|      * equals(null, "abc")  = false | 
|      * equals("abc", null)  = false | 
|      * equals("abc", "abc") = true | 
|      * equals("abc", "ABC") = false | 
|      * </pre> | 
|      *  | 
|      * @param str1 要比较的字符串1 | 
|      * @param str2 要比较的字符串2 | 
|      *  | 
|      * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code> | 
|      */ | 
|     public static boolean equals(String str1, String str2) { | 
|         if (str1 == null) { | 
|             return str2 == null; | 
|         } | 
|   | 
|         return str1.equals(str2); | 
|     } | 
|   | 
|     /** | 
|      * 比较两个字符串(大小写不敏感)。 | 
|      *  | 
|      * <pre> | 
|      * equalsIgnoreCase(null, null)   = true | 
|      * equalsIgnoreCase(null, "abc")  = false | 
|      * equalsIgnoreCase("abc", null)  = false | 
|      * equalsIgnoreCase("abc", "abc") = true | 
|      * equalsIgnoreCase("abc", "ABC") = true | 
|      * </pre> | 
|      *  | 
|      * @param str1 要比较的字符串1 | 
|      * @param str2 要比较的字符串2 | 
|      *  | 
|      * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code> | 
|      */ | 
|     public static boolean equalsIgnoreCase(String str1, String str2) { | 
|         if (str1 == null) { | 
|             return str2 == null; | 
|         } | 
|   | 
|         return str1.equalsIgnoreCase(str2); | 
|     } | 
|   | 
|     /** | 
|      * 格式化文本, {} 表示占位符<br> | 
|      * 例如:format("aaa {} ccc", "bbb")   ---->    aaa bbb ccc | 
|      *  | 
|      * @param template 文本模板,被替换的部分用 {} 表示 | 
|      * @param values 参数值 | 
|      * @return 格式化后的文本 | 
|      */ | 
|     public static String format(String template, Object... values) { | 
|         if (CollectionKit.isEmpty(values) || isBlank(template)) { | 
|             return template; | 
|         } | 
|   | 
|         final StringBuilder sb = new StringBuilder(); | 
|         final int length = template.length(); | 
|   | 
|         int valueIndex = 0; | 
|         char currentChar; | 
|         for (int i = 0; i < length; i++) { | 
|             if (valueIndex >= values.length) { | 
|                 sb.append(sub(template, i, length)); | 
|                 break; | 
|             } | 
|   | 
|             currentChar = template.charAt(i); | 
|             if (currentChar == '{') { | 
|                 final char nextChar = template.charAt(++i); | 
|                 if (nextChar == '}') { | 
|                     sb.append(values[valueIndex++]); | 
|                 } else { | 
|                     sb.append('{').append(nextChar); | 
|                 } | 
|             } else { | 
|                 sb.append(currentChar); | 
|             } | 
|   | 
|         } | 
|   | 
|         return sb.toString(); | 
|     } | 
|   | 
|     /** | 
|      * 格式化文本,使用 {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(String template, Map<?, ?> map) { | 
|         if (null == map || map.isEmpty()) { | 
|             return template; | 
|         } | 
|   | 
|         for (Entry<?, ?> entry : map.entrySet()) { | 
|             template = template.replace("{" + entry.getKey() + "}", entry.getValue().toString()); | 
|         } | 
|         return template; | 
|     } | 
|      | 
|     /** | 
|      * 编码字符串 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 | 
|      * @return 编码后的字节码 | 
|      */ | 
|     public static byte[] bytes(String str, String charset) { | 
|         return bytes(str, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); | 
|     } | 
|   | 
|     /** | 
|      * 编码字符串 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 | 
|      * @return 编码后的字节码 | 
|      */ | 
|     public static byte[] bytes(String str, Charset charset) { | 
|         if (str == null) { | 
|             return null; | 
|         } | 
|   | 
|         if (null == charset) { | 
|             return str.getBytes(); | 
|         } | 
|         return str.getBytes(charset); | 
|     } | 
|      | 
|     /** | 
|      * 将byte数组转为字符串 | 
|      *  | 
|      * @param bytes byte数组 | 
|      * @param charset 字符集 | 
|      * @return 字符串 | 
|      */ | 
|     public static String str(byte[] bytes, String charset) { | 
|         return str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); | 
|     } | 
|   | 
|     /** | 
|      * 解码字节码 | 
|      *  | 
|      * @param data 字符串 | 
|      * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 | 
|      * @return 解码后的字符串 | 
|      */ | 
|     public static String str(byte[] data, Charset charset) { | 
|         if (data == null) { | 
|             return null; | 
|         } | 
|   | 
|         if (null == charset) { | 
|             return new String(data); | 
|         } | 
|         return new String(data, charset); | 
|     } | 
|      | 
|     /** | 
|      * 将编码的byteBuffer数据转换为字符串 | 
|      * @param data 数据 | 
|      * @param charset 字符集,如果为空使用当前系统字符集 | 
|      * @return 字符串 | 
|      */ | 
|     public static String str(ByteBuffer data, String charset){ | 
|         if(data == null) { | 
|             return null; | 
|         } | 
|          | 
|         return str(data, Charset.forName(charset)); | 
|     } | 
|      | 
|     /** | 
|      * 将编码的byteBuffer数据转换为字符串 | 
|      * @param data 数据 | 
|      * @param charset 字符集,如果为空使用当前系统字符集 | 
|      * @return 字符串 | 
|      */ | 
|     public static String str(ByteBuffer data, Charset charset){ | 
|         if(null == charset) { | 
|             charset = Charset.defaultCharset(); | 
|         } | 
|         return charset.decode(data).toString(); | 
|     } | 
|      | 
|     /** | 
|      * 字符串转换为byteBuffer | 
|      * @param str 字符串 | 
|      * @param charset 编码 | 
|      * @return byteBuffer | 
|      */ | 
|     public static ByteBuffer byteBuffer(String str, String charset) { | 
|         return ByteBuffer.wrap(StrKit.bytes(str, charset)); | 
|     } | 
|   | 
|     /** | 
|      * 以 conjunction 为分隔符将多个对象转换为字符串 | 
|      *  | 
|      * @param conjunction 分隔符 | 
|      * @param objs 数组 | 
|      * @return 连接后的字符串 | 
|      */ | 
|     public static String join(String conjunction, Object... objs) { | 
|         StringBuilder sb = new StringBuilder(); | 
|         boolean isFirst = true; | 
|         for (Object item : objs) { | 
|             if (isFirst) { | 
|                 isFirst = false; | 
|             } else { | 
|                 sb.append(conjunction); | 
|             } | 
|             sb.append(item); | 
|         } | 
|         return sb.toString(); | 
|     } | 
|      | 
|     /** | 
|      * 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。</br> | 
|      * 例如:HelloWorld->hello_world | 
|      * | 
|      * @param camelCaseStr 转换前的驼峰式命名的字符串 | 
|      * @return 转换后下划线大写方式命名的字符串 | 
|      */ | 
|     public static String toUnderlineCase(String camelCaseStr) { | 
|         if (camelCaseStr == null) { | 
|             return null; | 
|         } | 
|   | 
|         final int length = camelCaseStr.length(); | 
|         StringBuilder sb = new StringBuilder(); | 
|         char c; | 
|         boolean isPreUpperCase = false; | 
|         for (int i = 0; i < length; i++) { | 
|             c = camelCaseStr.charAt(i); | 
|             boolean isNextUpperCase = true; | 
|             if (i < (length - 1)) { | 
|                 isNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1)); | 
|             } | 
|             if (Character.isUpperCase(c)) { | 
|                 if (!isPreUpperCase || !isNextUpperCase) { | 
|                     if (i > 0) sb.append(UNDERLINE); | 
|                 } | 
|                 isPreUpperCase = true; | 
|             } else { | 
|                 isPreUpperCase = false; | 
|             } | 
|             sb.append(Character.toLowerCase(c)); | 
|         } | 
|         return sb.toString(); | 
|     } | 
|   | 
|     /** | 
|      * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br> | 
|      * 例如:hello_world->HelloWorld | 
|      * | 
|      * @param name 转换前的下划线大写方式命名的字符串 | 
|      * @return 转换后的驼峰式命名的字符串 | 
|      */ | 
|     public static String toCamelCase(String name) { | 
|         if (name == null) { | 
|             return null; | 
|         } | 
|         if (name.contains(UNDERLINE)) { | 
|             name = name.toLowerCase(); | 
|   | 
|             StringBuilder sb = new StringBuilder(name.length()); | 
|             boolean upperCase = false; | 
|             for (int i = 0; i < name.length(); i++) { | 
|                 char c = name.charAt(i); | 
|   | 
|                 if (c == '_') { | 
|                     upperCase = true; | 
|                 } else if (upperCase) { | 
|                     sb.append(Character.toUpperCase(c)); | 
|                     upperCase = false; | 
|                 } else { | 
|                     sb.append(c); | 
|                 } | 
|             } | 
|             return sb.toString(); | 
|         } else | 
|             return name; | 
|     } | 
|   | 
|     /** | 
|      * 包装指定字符串 | 
|      *  | 
|      * @param str 被包装的字符串 | 
|      * @param prefix 前缀 | 
|      * @param suffix 后缀 | 
|      * @return 包装后的字符串 | 
|      */ | 
|     public static String wrap(String str, String prefix, String suffix) { | 
|         return format("{}{}{}", prefix, str, suffix); | 
|     } | 
|   | 
|     /** | 
|      * 指定字符串是否被包装 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param prefix 前缀 | 
|      * @param suffix 后缀 | 
|      * @return 是否被包装 | 
|      */ | 
|     public static boolean isWrap(String str, String prefix, String suffix) { | 
|         return str.startsWith(prefix) && str.endsWith(suffix); | 
|     } | 
|   | 
|     /** | 
|      * 指定字符串是否被同一字符包装(前后都有这些字符串) | 
|      *  | 
|      * @param str 字符串 | 
|      * @param wrapper 包装字符串 | 
|      * @return 是否被包装 | 
|      */ | 
|     public static boolean isWrap(String str, String wrapper) { | 
|         return isWrap(str, wrapper, wrapper); | 
|     } | 
|   | 
|     /** | 
|      * 指定字符串是否被同一字符包装(前后都有这些字符串) | 
|      *  | 
|      * @param str 字符串 | 
|      * @param wrapper 包装字符 | 
|      * @return 是否被包装 | 
|      */ | 
|     public static boolean isWrap(String str, char wrapper) { | 
|         return isWrap(str, wrapper, wrapper); | 
|     } | 
|   | 
|     /** | 
|      * 指定字符串是否被包装 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param prefixChar 前缀 | 
|      * @param suffixChar 后缀 | 
|      * @return 是否被包装 | 
|      */ | 
|     public static boolean isWrap(String str, char prefixChar, char suffixChar) { | 
|         return str.charAt(0) == prefixChar && str.charAt(str.length() - 1) == suffixChar; | 
|     } | 
|   | 
|     /** | 
|      * 补充字符串以满足最小长度 StrUtil.padPre("1", 3, '0');//"001" | 
|      *  | 
|      * @param str 字符串 | 
|      * @param minLength 最小长度 | 
|      * @param padChar 补充的字符 | 
|      * @return 补充后的字符串 | 
|      */ | 
|     public static String padPre(String str, int minLength, char padChar) { | 
|         if (str.length() >= minLength) { | 
|             return str; | 
|         } | 
|         StringBuilder sb = new StringBuilder(minLength); | 
|         for (int i = str.length(); i < minLength; i++) { | 
|             sb.append(padChar); | 
|         } | 
|         sb.append(str); | 
|         return sb.toString(); | 
|     } | 
|   | 
|     /** | 
|      * 补充字符串以满足最小长度 StrUtil.padEnd("1", 3, '0');//"100" | 
|      *  | 
|      * @param str 字符串 | 
|      * @param minLength 最小长度 | 
|      * @param padChar 补充的字符 | 
|      * @return 补充后的字符串 | 
|      */ | 
|     public static String padEnd(String str, int minLength, char padChar) { | 
|         if (str.length() >= minLength) { | 
|             return str; | 
|         } | 
|         StringBuilder sb = new StringBuilder(minLength); | 
|         sb.append(str); | 
|         for (int i = str.length(); i < minLength; i++) { | 
|             sb.append(padChar); | 
|         } | 
|         return sb.toString(); | 
|     } | 
|   | 
|     /** | 
|      * 创建StringBuilder对象 | 
|      *  | 
|      * @return StringBuilder对象 | 
|      */ | 
|     public static StringBuilder builder() { | 
|         return new StringBuilder(); | 
|     } | 
|   | 
|     /** | 
|      * 创建StringBuilder对象 | 
|      *  | 
|      * @return StringBuilder对象 | 
|      */ | 
|     public static StringBuilder builder(int capacity) { | 
|         return new StringBuilder(capacity); | 
|     } | 
|   | 
|     /** | 
|      * 创建StringBuilder对象 | 
|      *  | 
|      * @return StringBuilder对象 | 
|      */ | 
|     public static StringBuilder builder(String... strs) { | 
|         final StringBuilder sb = new StringBuilder(); | 
|         for (String str : strs) { | 
|             sb.append(str); | 
|         } | 
|         return sb; | 
|     } | 
|   | 
|     /** | 
|      * 获得StringReader | 
|      *  | 
|      * @param str 字符串 | 
|      * @return StringReader | 
|      */ | 
|     public static StringReader getReader(String str) { | 
|         return new StringReader(str); | 
|     } | 
|   | 
|     /** | 
|      * 获得StringWriter | 
|      *  | 
|      * @return StringWriter | 
|      */ | 
|     public static StringWriter getWriter() { | 
|         return new StringWriter(); | 
|     } | 
|   | 
|         /** | 
|      * 编码字符串 | 
|      *  | 
|      * @param str 字符串 | 
|      * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 | 
|      * @return 编码后的字节码 | 
|      */ | 
|     public static byte[] encode(String str, String charset) { | 
|         if (str == null) { | 
|             return null; | 
|         } | 
|   | 
|         if(isBlank(charset)) { | 
|             return str.getBytes(); | 
|         } | 
|         try { | 
|             return str.getBytes(charset); | 
|         } catch (UnsupportedEncodingException e) { | 
|             throw new RuntimeException(format("Charset [{}] unsupported!", charset)); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 解码字节码 | 
|      *  | 
|      * @param data 字符串 | 
|      * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 | 
|      * @return 解码后的字符串 | 
|      */ | 
|     public static String decode(byte[] data, String charset) { | 
|         if (data == null) { | 
|             return null; | 
|         } | 
|   | 
|         if(isBlank(charset)) { | 
|             return new String(data); | 
|         } | 
|         try { | 
|             return new String(data, charset); | 
|         } catch (UnsupportedEncodingException e) { | 
|             throw new RuntimeException(format("Charset [{}] unsupported!", charset)); | 
|         } | 
|     } | 
| } |