1874 lines
54 KiB
Java
1874 lines
54 KiB
Java
/**
|
||
* Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
|
||
* <p>
|
||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
* <p>
|
||
* http://www.gnu.org/licenses/lgpl.html
|
||
* <p>
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
package org.springblade.core.tool.utils;
|
||
|
||
import org.springblade.core.tool.support.StrFormatter;
|
||
import org.springblade.core.tool.support.StrSpliter;
|
||
import org.springframework.lang.Nullable;
|
||
import org.springframework.util.Assert;
|
||
import org.springframework.util.StringUtils;
|
||
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.stream.Stream;
|
||
|
||
/**
|
||
* 继承自Spring util的工具类,减少jar依赖
|
||
*
|
||
* @author L.cm
|
||
*/
|
||
public class StringUtil extends org.springframework.util.StringUtils {
|
||
|
||
public static final int INDEX_NOT_FOUND = -1;
|
||
/**
|
||
* <p>The maximum size to which the padding constant(s) can expand.</p>
|
||
*/
|
||
private static final int PAD_LIMIT = 8192;
|
||
|
||
/**
|
||
* 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);
|
||
}
|
||
|
||
/**
|
||
* 判断一个字符串是否是数字
|
||
*
|
||
* @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;
|
||
}
|
||
|
||
/**
|
||
* 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);
|
||
}
|
||
|
||
/**
|
||
* 生成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("[ `·•<C2B7>\\f\\t\\v\\s]", "");
|
||
}
|
||
|
||
|
||
private static final String S_INT = "0123456789";
|
||
private static final String S_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||
private static final String S_ALL = S_INT + S_STR;
|
||
|
||
/**
|
||
* 随机数生成
|
||
*
|
||
* @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 "";
|
||
}
|
||
Assert.isTrue(count > 0, "Requested random string length " + count + " is less than 0.");
|
||
final ThreadLocalRandom random = ThreadLocalRandom.current();
|
||
char[] buffer = new char[count];
|
||
for (int i = 0; i < count; i++) {
|
||
if (RandomType.INT == randomType) {
|
||
buffer[i] = S_INT.charAt(random.nextInt(S_INT.length()));
|
||
} else if (RandomType.STRING == randomType) {
|
||
buffer[i] = S_STR.charAt(random.nextInt(S_STR.length()));
|
||
} else {
|
||
buffer[i] = S_ALL.charAt(random.nextInt(S_ALL.length()));
|
||
}
|
||
}
|
||
return new String(buffer);
|
||
}
|
||
|
||
/**
|
||
* 格式化文本, {} 表示占位符<br>
|
||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
||
* 例:<br>
|
||
* 通常使用:format("this is {} for {}", "a", "b") =》 this is a for b<br>
|
||
* 转义{}: format("this is \\{} for {}", "a", "b") =》 this is \{} for a<br>
|
||
* 转义\: format("this is \\\\{} for {}", "a", "b") =》 this is \a for b<br>
|
||
*
|
||
* @param template 文本模板,被替换的部分用 {} 表示
|
||
* @param params 参数值
|
||
* @return 格式化后的文本
|
||
*/
|
||
public static String format(CharSequence template, Object... params) {
|
||
if (null == template) {
|
||
return null;
|
||
}
|
||
if (Func.isEmpty(params) || isBlank(template)) {
|
||
return template.toString();
|
||
}
|
||
return StrFormatter.format(template.toString(), params);
|
||
}
|
||
|
||
/**
|
||
* 有序的格式化文本,使用{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 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 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 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 lowerFirst(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 lowerFirst(String str) {
|
||
char firstChar = str.charAt(0);
|
||
if (firstChar >= StringPool.U_A && firstChar <= StringPool.U_Z) {
|
||
char[] arr = str.toCharArray();
|
||
arr[0] += (StringPool.L_A - StringPool.U_A);
|
||
return new String(arr);
|
||
}
|
||
return str;
|
||
}
|
||
|
||
/**
|
||
* 首字母变大写
|
||
*
|
||
* @param str 字符串
|
||
* @return {String}
|
||
*/
|
||
public static String upperFirst(String str) {
|
||
char firstChar = str.charAt(0);
|
||
if (firstChar >= StringPool.L_A && firstChar <= StringPool.L_Z) {
|
||
char[] arr = str.toCharArray();
|
||
arr[0] -= (StringPool.L_A - StringPool.U_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, "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 equals(CharSequence str1, CharSequence str2) {
|
||
return equals(str1, str2, false);
|
||
}
|
||
|
||
/**
|
||
* 比较两个字符串(大小写不敏感)。
|
||
*
|
||
* <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(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 StringBuilder对象
|
||
*/
|
||
public static StringBuilder builder() {
|
||
return new StringBuilder();
|
||
}
|
||
|
||
/**
|
||
* 创建StringBuilder对象
|
||
*
|
||
* @param capacity 初始大小
|
||
* @return StringBuilder对象
|
||
*/
|
||
public static StringBuilder builder(int capacity) {
|
||
return new StringBuilder(capacity);
|
||
}
|
||
|
||
/**
|
||
* 创建StringBuilder对象
|
||
*
|
||
* @param strs 初始字符串列表
|
||
* @return StringBuilder对象
|
||
*/
|
||
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 StringBuilder对象
|
||
*/
|
||
public static StringBuilder appendBuilder(StringBuilder sb, CharSequence... strs) {
|
||
for (CharSequence str : strs) {
|
||
sb.append(str);
|
||
}
|
||
return sb;
|
||
}
|
||
|
||
/**
|
||
* 获得StringReader
|
||
*
|
||
* @param str 字符串
|
||
* @return StringReader
|
||
*/
|
||
public static StringReader getReader(CharSequence str) {
|
||
if (null == str) {
|
||
return null;
|
||
}
|
||
return new StringReader(str.toString());
|
||
}
|
||
|
||
/**
|
||
* 获得StringWriter
|
||
*
|
||
* @return StringWriter
|
||
*/
|
||
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) {
|
||
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 = lowerFirst(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 = lowerFirst(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 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;
|
||
}
|
||
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Returns padding using the specified delimiter repeated
|
||
* to a given length.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.repeat('e', 0) = ""
|
||
* StringUtils.repeat('e', 3) = "eee"
|
||
* StringUtils.repeat('e', -2) = ""
|
||
* </pre>
|
||
*
|
||
* <p>Note: this method does not support padding with
|
||
* <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
|
||
* as they require a pair of {@code char}s to be represented.
|
||
* </p>
|
||
*
|
||
* @param ch character to repeat
|
||
* @param repeat number of times to repeat char, negative treated as zero
|
||
* @return String with repeated character
|
||
*/
|
||
public static String repeat(final char ch, final int repeat) {
|
||
if (repeat <= 0) {
|
||
return StringPool.EMPTY;
|
||
}
|
||
final char[] buf = new char[repeat];
|
||
Arrays.fill(buf, ch);
|
||
return new String(buf);
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Gets the leftmost {@code len} characters of a String.</p>
|
||
*
|
||
* <p>If {@code len} characters are not available, or the
|
||
* String is {@code null}, the String will be returned without
|
||
* an exception. An empty String is returned if len is negative.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.left(null, *) = null
|
||
* StringUtils.left(*, -ve) = ""
|
||
* StringUtils.left("", *) = ""
|
||
* StringUtils.left("abc", 0) = ""
|
||
* StringUtils.left("abc", 2) = "ab"
|
||
* StringUtils.left("abc", 4) = "abc"
|
||
* </pre>
|
||
*
|
||
* @param str the CharSequence to get the leftmost characters from, may be null
|
||
* @param len the length of the required String
|
||
* @return the leftmost characters, {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String left(@Nullable final String str, final int len) {
|
||
if (str == null) {
|
||
return null;
|
||
}
|
||
if (len < 0) {
|
||
return StringPool.EMPTY;
|
||
}
|
||
if (str.length() <= len) {
|
||
return str;
|
||
}
|
||
return str.substring(0, len);
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Gets the rightmost {@code len} characters of a String.</p>
|
||
*
|
||
* <p>If {@code len} characters are not available, or the String
|
||
* is {@code null}, the String will be returned without an
|
||
* an exception. An empty String is returned if len is negative.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.right(null, *) = null
|
||
* StringUtils.right(*, -ve) = ""
|
||
* StringUtils.right("", *) = ""
|
||
* StringUtils.right("abc", 0) = ""
|
||
* StringUtils.right("abc", 2) = "bc"
|
||
* StringUtils.right("abc", 4) = "abc"
|
||
* </pre>
|
||
*
|
||
* @param str the String to get the rightmost characters from, may be null
|
||
* @param len the length of the required String
|
||
* @return the rightmost characters, {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String right(@Nullable final String str, final int len) {
|
||
if (str == null) {
|
||
return null;
|
||
}
|
||
if (len < 0) {
|
||
return StringPool.EMPTY;
|
||
}
|
||
int length = str.length();
|
||
if (length <= len) {
|
||
return str;
|
||
}
|
||
return str.substring(length - len);
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Right pad a String with spaces (' ').</p>
|
||
*
|
||
* <p>The String is padded to the size of {@code size}.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.rightPad(null, *) = null
|
||
* StringUtils.rightPad("", 3) = " "
|
||
* StringUtils.rightPad("bat", 3) = "bat"
|
||
* StringUtils.rightPad("bat", 5) = "bat "
|
||
* StringUtils.rightPad("bat", 1) = "bat"
|
||
* StringUtils.rightPad("bat", -1) = "bat"
|
||
* </pre>
|
||
*
|
||
* @param str the String to pad out, may be null
|
||
* @param size the size to pad to
|
||
* @return right padded String or original String if no padding is necessary,
|
||
* {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String rightPad(@Nullable final String str, final int size) {
|
||
return rightPad(str, size, CharPool.SPACE);
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Right pad a String with a specified character.</p>
|
||
*
|
||
* <p>The String is padded to the size of {@code size}.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.rightPad(null, *, *) = null
|
||
* StringUtils.rightPad("", 3, 'z') = "zzz"
|
||
* StringUtils.rightPad("bat", 3, 'z') = "bat"
|
||
* StringUtils.rightPad("bat", 5, 'z') = "batzz"
|
||
* StringUtils.rightPad("bat", 1, 'z') = "bat"
|
||
* StringUtils.rightPad("bat", -1, 'z') = "bat"
|
||
* </pre>
|
||
*
|
||
* @param str the String to pad out, may be null
|
||
* @param size the size to pad to
|
||
* @param padChar the character to pad with
|
||
* @return right padded String or original String if no padding is necessary,
|
||
* {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String rightPad(@Nullable final String str, final int size, final char padChar) {
|
||
if (str == null) {
|
||
return null;
|
||
}
|
||
final int pads = size - str.length();
|
||
if (pads <= 0) {
|
||
// returns original String when possible
|
||
return str;
|
||
}
|
||
if (pads > PAD_LIMIT) {
|
||
return rightPad(str, size, String.valueOf(padChar));
|
||
}
|
||
return str.concat(repeat(padChar, pads));
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Right pad a String with a specified String.</p>
|
||
*
|
||
* <p>The String is padded to the size of {@code size}.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.rightPad(null, *, *) = null
|
||
* StringUtils.rightPad("", 3, "z") = "zzz"
|
||
* StringUtils.rightPad("bat", 3, "yz") = "bat"
|
||
* StringUtils.rightPad("bat", 5, "yz") = "batyz"
|
||
* StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
|
||
* StringUtils.rightPad("bat", 1, "yz") = "bat"
|
||
* StringUtils.rightPad("bat", -1, "yz") = "bat"
|
||
* StringUtils.rightPad("bat", 5, null) = "bat "
|
||
* StringUtils.rightPad("bat", 5, "") = "bat "
|
||
* </pre>
|
||
*
|
||
* @param str the String to pad out, may be null
|
||
* @param size the size to pad to
|
||
* @param padStr the String to pad with, null or empty treated as single space
|
||
* @return right padded String or original String if no padding is necessary,
|
||
* {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String rightPad(@Nullable final String str, final int size, String padStr) {
|
||
if (str == null) {
|
||
return null;
|
||
}
|
||
if (!StringUtils.hasLength(padStr)) {
|
||
padStr = StringPool.SPACE;
|
||
}
|
||
final int padLen = padStr.length();
|
||
final int strLen = str.length();
|
||
final int pads = size - strLen;
|
||
if (pads <= 0) {
|
||
// returns original String when possible
|
||
return str;
|
||
}
|
||
if (padLen == 1 && pads <= PAD_LIMIT) {
|
||
return rightPad(str, size, padStr.charAt(0));
|
||
}
|
||
if (pads == padLen) {
|
||
return str.concat(padStr);
|
||
} else if (pads < padLen) {
|
||
return str.concat(padStr.substring(0, pads));
|
||
} else {
|
||
final char[] padding = new char[pads];
|
||
final char[] padChars = padStr.toCharArray();
|
||
for (int i = 0; i < pads; i++) {
|
||
padding[i] = padChars[i % padLen];
|
||
}
|
||
return str.concat(new String(padding));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Left pad a String with spaces (' ').</p>
|
||
*
|
||
* <p>The String is padded to the size of {@code size}.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.leftPad(null, *) = null
|
||
* StringUtils.leftPad("", 3) = " "
|
||
* StringUtils.leftPad("bat", 3) = "bat"
|
||
* StringUtils.leftPad("bat", 5) = " bat"
|
||
* StringUtils.leftPad("bat", 1) = "bat"
|
||
* StringUtils.leftPad("bat", -1) = "bat"
|
||
* </pre>
|
||
*
|
||
* @param str the String to pad out, may be null
|
||
* @param size the size to pad to
|
||
* @return left padded String or original String if no padding is necessary,
|
||
* {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String leftPad(@Nullable final String str, final int size) {
|
||
return leftPad(str, size, CharPool.SPACE);
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Left pad a String with a specified character.</p>
|
||
*
|
||
* <p>Pad to a size of {@code size}.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.leftPad(null, *, *) = null
|
||
* StringUtils.leftPad("", 3, 'z') = "zzz"
|
||
* StringUtils.leftPad("bat", 3, 'z') = "bat"
|
||
* StringUtils.leftPad("bat", 5, 'z') = "zzbat"
|
||
* StringUtils.leftPad("bat", 1, 'z') = "bat"
|
||
* StringUtils.leftPad("bat", -1, 'z') = "bat"
|
||
* </pre>
|
||
*
|
||
* @param str the String to pad out, may be null
|
||
* @param size the size to pad to
|
||
* @param padChar the character to pad with
|
||
* @return left padded String or original String if no padding is necessary,
|
||
* {@code null} if null String input
|
||
* @since 2.0
|
||
*/
|
||
@Nullable
|
||
public static String leftPad(@Nullable final String str, final int size, final char padChar) {
|
||
if (str == null) {
|
||
return null;
|
||
}
|
||
final int pads = size - str.length();
|
||
if (pads <= 0) {
|
||
// returns original String when possible
|
||
return str;
|
||
}
|
||
if (pads > PAD_LIMIT) {
|
||
return leftPad(str, size, String.valueOf(padChar));
|
||
}
|
||
return repeat(padChar, pads).concat(str);
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Left pad a String with a specified String.</p>
|
||
*
|
||
* <p>Pad to a size of {@code size}.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.leftPad(null, *, *) = null
|
||
* StringUtils.leftPad("", 3, "z") = "zzz"
|
||
* StringUtils.leftPad("bat", 3, "yz") = "bat"
|
||
* StringUtils.leftPad("bat", 5, "yz") = "yzbat"
|
||
* StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
|
||
* StringUtils.leftPad("bat", 1, "yz") = "bat"
|
||
* StringUtils.leftPad("bat", -1, "yz") = "bat"
|
||
* StringUtils.leftPad("bat", 5, null) = " bat"
|
||
* StringUtils.leftPad("bat", 5, "") = " bat"
|
||
* </pre>
|
||
*
|
||
* @param str the String to pad out, may be null
|
||
* @param size the size to pad to
|
||
* @param padStr the String to pad with, null or empty treated as single space
|
||
* @return left padded String or original String if no padding is necessary,
|
||
* {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String leftPad(@Nullable final String str, final int size, String padStr) {
|
||
if (str == null) {
|
||
return null;
|
||
}
|
||
if (!StringUtils.hasLength(padStr)) {
|
||
padStr = StringPool.SPACE;
|
||
}
|
||
final int padLen = padStr.length();
|
||
final int strLen = str.length();
|
||
final int pads = size - strLen;
|
||
if (pads <= 0) {
|
||
// returns original String when possible
|
||
return str;
|
||
}
|
||
if (padLen == 1 && pads <= PAD_LIMIT) {
|
||
return leftPad(str, size, padStr.charAt(0));
|
||
}
|
||
if (pads == padLen) {
|
||
return padStr.concat(str);
|
||
} else if (pads < padLen) {
|
||
return padStr.substring(0, pads).concat(str);
|
||
} else {
|
||
final char[] padding = new char[pads];
|
||
final char[] padChars = padStr.toCharArray();
|
||
for (int i = 0; i < pads; i++) {
|
||
padding[i] = padChars[i % padLen];
|
||
}
|
||
return new String(padding).concat(str);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 参考自 commons lang 微调
|
||
*
|
||
* <p>Gets {@code len} characters from the middle of a String.</p>
|
||
*
|
||
* <p>If {@code len} characters are not available, the remainder
|
||
* of the String will be returned without an exception. If the
|
||
* String is {@code null}, {@code null} will be returned.
|
||
* An empty String is returned if len is negative or exceeds the
|
||
* length of {@code str}.</p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.mid(null, *, *) = null
|
||
* StringUtils.mid(*, *, -ve) = ""
|
||
* StringUtils.mid("", 0, *) = ""
|
||
* StringUtils.mid("abc", 0, 2) = "ab"
|
||
* StringUtils.mid("abc", 0, 4) = "abc"
|
||
* StringUtils.mid("abc", 2, 4) = "c"
|
||
* StringUtils.mid("abc", 4, 2) = ""
|
||
* StringUtils.mid("abc", -2, 2) = "ab"
|
||
* </pre>
|
||
*
|
||
* @param str the String to get the characters from, may be null
|
||
* @param pos the position to start from, negative treated as zero
|
||
* @param len the length of the required String
|
||
* @return the middle characters, {@code null} if null String input
|
||
*/
|
||
@Nullable
|
||
public static String mid(@Nullable final String str, int pos, final int len) {
|
||
if (str == null) {
|
||
return null;
|
||
}
|
||
int length = str.length();
|
||
if (len < 0 || pos > length) {
|
||
return StringPool.EMPTY;
|
||
}
|
||
if (pos < 0) {
|
||
pos = 0;
|
||
}
|
||
if (length <= pos + len) {
|
||
return str.substring(pos);
|
||
}
|
||
return str.substring(pos, pos + len);
|
||
}
|
||
|
||
}
|
||
|