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

org.macrocloud.kernel.toolkit.utils.StringUtil Maven / Gradle / Ivy

package org.macrocloud.kernel.toolkit.utils;

import org.macrocloud.kernel.toolkit.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 macro
 */
public class StringUtil extends org.springframework.util.StringUtils {

	/** The Constant INDEX_NOT_FOUND. */
	public static final int INDEX_NOT_FOUND = -1;

	/**
	 * Check whether the given {@code CharSequence} contains actual text.
	 * 

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. *

	 * StringUtil.isBlank(null) = true
	 * StringUtil.isBlank("") = true
	 * StringUtil.isBlank(" ") = true
	 * StringUtil.isBlank("12345") = false
	 * StringUtil.isBlank(" 12345 ") = false
	 * 
* * @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); } /** *

Checks if a CharSequence is not empty (""), not null and not whitespace only.

*
	 * StringUtil.isNotBlank(null)	  = false
	 * StringUtil.isNotBlank("")		= false
	 * StringUtil.isNotBlank(" ")	   = false
	 * StringUtil.isNotBlank("bob")	 = true
	 * StringUtil.isNotBlank("  bob  ") = true
	 * 
* * @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中对应的值 *

* use: format("my name is ${name}, and i like ${like}!", {"name":"macro", "like": "Java"}). * * @param message 需要转换的字符串 * @param params 转换所需的键值对集合 * @return 转换后的字符串 */ public static String format(@Nullable String message, @Nullable Map 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 规则 *

* use: format("my name is {}, and i like {}!", "macro", "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). *

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). *

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). *

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). *

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); } /** * 字符串是否符合指定的 表达式 * *

* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" *

. * * @param pattern 表达式 * @param str 字符串 * @return 是否匹配 */ public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) { return PatternMatchUtils.simpleMatch(pattern, str); } /** * 字符串是否符合指定的 表达式 * *

* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" *

. * * @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}做为占位符
* 例:
* 通常使用:format("this is {0} for {1}", "a", "b") =》 this is a for b
. * * @param pattern 文本格式 * @param arguments 参数 * @return 格式化后的文本 */ public static String indexedFormat(CharSequence pattern, Object... arguments) { return MessageFormat.format(pattern.toString(), arguments); } /** * 格式化文本,使用 {varName} 占位
* 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 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 splitTrim(CharSequence str, char separator) { return splitTrim(str, separator, -1); } /** * 切分字符串,去除切分后每个元素两边的空白符,去除空白项. * * @param str 被切分的字符串 * @param separator 分隔符字符 * @return 切分后的集合 * @since 3.2.0 */ public static List 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 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 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 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 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 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; } /** * 是否包含特定字符,忽略大小写,如果给定两个参数都为null,返回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()); } /** * 查找指定字符串是否包含指定字符串列表中的任意一个字符串
* 忽略大小写. * * @param str 指定字符串 * @param testStrs 需要检查的字符串数组 * @return 是否包含任意一个字符串 * @since 3.2.0 */ public static boolean containsAnyIgnoreCase(CharSequence str, CharSequence... testStrs) { return null != getContainsStrIgnoreCase(str, testStrs); } /** * 查找指定字符串是否包含指定字符串列表中的任意一个字符串,如果包含返回找到的第一个字符串
* 忽略大小写. * * @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
* index从0开始计算,最后一个字符为-1
* 如果from和to位置一样,返回 ""
* 如果from或to为负数,则按照length从后向前数位置,如果绝对值大于字符串长度,则from归到0,to归到length
* 如果经过修正的index中from大于to,则互换from和to example:
* abcdefgh 2 3 =》 c
* abcdefgh 2 -3 =》 cde
. * * @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); } /** * 截取分隔字符串之前的字符串,不包括分隔字符串
* 如果给定的字符串为空串(null或"")或者分隔字符串为null,返回原字符串
* 如果分隔字符串为空串"",则返回空串,如果分隔字符串未找到,返回原字符串 *

* 栗子: * *

	 * 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"
	 * 
* * @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); } /** * 截取分隔字符串之后的字符串,不包括分隔字符串
* 如果给定的字符串为空串(null或""),返回原字符串
* 如果分隔字符串为空串(null或""),则返回空串,如果分隔字符串未找到,返回空串 *

* 栗子: * *

	 * 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"
	 * 
* * @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()); } /** * 截取指定字符串中间部分,不包括标识字符串
*

* 栗子: * *

	 * 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"
	 * 
* * @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; } /** * 截取指定字符串中间部分,不包括标识字符串
*

* 栗子: * *

	 * StringUtil.subBetween(null, *)            = null
	 * StringUtil.subBetween("", "")             = ""
	 * StringUtil.subBetween("", "tag")          = null
	 * StringUtil.subBetween("tagabctag", null)  = null
	 * StringUtil.subBetween("tagabctag", "")    = ""
	 * StringUtil.subBetween("tagabctag", "tag") = "abc"
	 * 
* * @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; } /** * 指定范围内查找字符串,忽略大小写
* *
	 * 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
	 * 
* * @param str 字符串 * @param searchStr 需要查找位置的字符串 * @return 位置 * @since 3.2.1 */ public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { return indexOfIgnoreCase(str, searchStr, 0); } /** * 指定范围内查找字符串 * *
	 * 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
	 * 
* * @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; } /** * 指定范围内查找字符串,忽略大小写
. * * @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()); } /** * 指定范围内查找字符串,忽略大小写
. * * @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); } /** * 指定范围内查找字符串
. * * @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 次出现的位置。
* 此方法来自:Apache-Commons-Lang *

* 栗子(*代表任意字符): * *

	 * 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
	 * 
* * @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; } /** * 截取两个字符串的不同部分(长度一致),判断截取的子串是否相同
* 任意一个字符串为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); } /** * 比较两个字符串(大小写敏感)。 * *
	 * equalsIgnoreCase(null, null)   = true
	 * equalsIgnoreCase(null, "abc")  = false
	 * equalsIgnoreCase("abc", null)  = false
	 * equalsIgnoreCase("abc", "abc") = true
	 * equalsIgnoreCase("abc", "ABC") = true
	 * 
. * * @param str1 要比较的字符串1 * @param str2 要比较的字符串2 * @return 如果两个字符串相同,或者都是null,则返回true */ public static boolean equals(CharSequence str1, CharSequence str2) { return equals(str1, str2, false); } /** * 比较两个字符串(大小写不敏感)。 * *
	 * equalsIgnoreCase(null, null)   = true
	 * equalsIgnoreCase(null, "abc")  = false
	 * equalsIgnoreCase("abc", null)  = false
	 * equalsIgnoreCase("abc", "abc") = true
	 * equalsIgnoreCase("abc", "ABC") = true
	 * 
. * * @param str1 要比较的字符串1 * @param str2 要比较的字符串2 * @return 如果两个字符串相同,或者都是null,则返回true */ public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) { return equals(str1, str2, true); } /** * 比较两个字符串是否相等。. * * @param str1 要比较的字符串1 * @param str2 要比较的字符串2 * @param ignoreCase 是否忽略大小写 * @return 如果两个字符串相同,或者都是null,则返回true * @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(); } /** * 统计指定内容中包含指定字符串的数量
* 参数为 {@code null} 或者 "" 返回 {@code 0}. * *
	 * 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
	 * 
* * @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) { 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) { 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) { 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) { 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(); } /** * Upper first. * * @param Str the str * @return the string */ public static String upperFirst(String Str) { return Str; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy