From 9b4433fddf5b401edb0aace8a404ac733b122702 Mon Sep 17 00:00:00 2001 From: 田源 <tianyuan@vci-tech.com> Date: 星期四, 03 四月 2025 14:35:02 +0800 Subject: [PATCH] 添加非密字段显示 --- Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java | 1577 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1,577 insertions(+), 0 deletions(-) diff --git a/Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java b/Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java new file mode 100644 index 0000000..31b0b0a --- /dev/null +++ b/Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java @@ -0,0 +1,1577 @@ +/* + * Copyright (c) 2018-2028, DreamLu All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: DreamLu 鍗㈡槬姊� (596392912@qq.com) + */ +package org.springblade.core.tool.utils; + +import org.springblade.core.tool.support.StrSpliter; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.PatternMatchUtils; +import org.springframework.web.util.HtmlUtils; + +import java.io.StringReader; +import java.io.StringWriter; +import java.text.MessageFormat; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +/** + * 缁ф壙鑷猄pring util鐨勫伐鍏风被锛屽噺灏慾ar渚濊禆 + * + * @author L.cm + */ +public class StringUtil extends org.springframework.util.StringUtils { + + public static final int INDEX_NOT_FOUND = -1; + + /** + * Check whether the given {@code CharSequence} contains actual <em>text</em>. + * <p>More specifically, this method returns {@code true} if the + * {@code CharSequence} is not {@code null}, its length is greater than + * 0, and it contains at least one non-whitespace character. + * <pre class="code"> + * StringUtil.isBlank(null) = true + * StringUtil.isBlank("") = true + * StringUtil.isBlank(" ") = true + * StringUtil.isBlank("12345") = false + * StringUtil.isBlank(" 12345 ") = false + * </pre> + * + * @param cs the {@code CharSequence} to check (may be {@code null}) + * @return {@code true} if the {@code CharSequence} is not {@code null}, + * its length is greater than 0, and it does not contain whitespace only + * @see Character#isWhitespace + */ + public static boolean isBlank(final CharSequence cs) { + return !StringUtil.hasText(cs); + } + + /** + * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> + * <pre> + * StringUtil.isNotBlank(null) = false + * StringUtil.isNotBlank("") = false + * StringUtil.isNotBlank(" ") = false + * StringUtil.isNotBlank("bob") = true + * StringUtil.isNotBlank(" bob ") = true + * </pre> + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is + * not empty and not null and not whitespace + * @see Character#isWhitespace + */ + public static boolean isNotBlank(final CharSequence cs) { + return StringUtil.hasText(cs); + } + + /** + * 鏈� 浠绘剰 涓�涓� Blank + * + * @param css CharSequence + * @return boolean + */ + public static boolean isAnyBlank(final CharSequence... css) { + if (ObjectUtil.isEmpty(css)) { + return true; + } + return Stream.of(css).anyMatch(StringUtil::isBlank); + } + + /** + * 鏄惁鍏ㄩ潪 Blank + * + * @param css CharSequence + * @return boolean + */ + public static boolean isNoneBlank(final CharSequence... css) { + if (ObjectUtil.isEmpty(css)) { + return false; + } + return Stream.of(css).allMatch(StringUtil::isNotBlank); + } + + /** + * 鏄惁鍏ㄤ负 Blank + * + * @param css CharSequence + * @return boolean + */ + public static boolean isAllBlank(final CharSequence... css) { + return Stream.of(css).allMatch(StringUtil::isBlank); + } + + /** + * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁鏄暟瀛� + * + * @param cs the CharSequence to check, may be null + * @return {boolean} + */ + public static boolean isNumeric(final CharSequence cs) { + if (isBlank(cs)) { + return false; + } + for (int i = cs.length(); --i >= 0; ) { + int chr = cs.charAt(i); + if (chr < 48 || chr > 57) { + return false; + } + } + return true; + } + + /** + * 灏嗗瓧绗︿覆涓壒瀹氭ā寮忕殑瀛楃杞崲鎴恗ap涓搴旂殑鍊� + * <p> + * use: format("my name is ${name}, and i like ${like}!", {"name":"L.cm", "like": "Java"}) + * + * @param message 闇�瑕佽浆鎹㈢殑瀛楃涓� + * @param params 杞崲鎵�闇�鐨勯敭鍊煎闆嗗悎 + * @return 杞崲鍚庣殑瀛楃涓� + */ + public static String format(@Nullable String message, @Nullable Map<String, ?> params) { + // message 涓� null 杩斿洖绌哄瓧绗︿覆 + if (message == null) { + return StringPool.EMPTY; + } + // 鍙傛暟涓� null 鎴栬�呬负绌� + if (params == null || params.isEmpty()) { + return message; + } + // 鏇挎崲鍙橀噺 + StringBuilder sb = new StringBuilder((int) (message.length() * 1.5)); + int cursor = 0; + for (int start, end; (start = message.indexOf(StringPool.DOLLAR_LEFT_BRACE, cursor)) != -1 && (end = message.indexOf(StringPool.RIGHT_BRACE, start)) != -1; ) { + sb.append(message, cursor, start); + String key = message.substring(start + 2, end); + Object value = params.get(StringUtil.trimWhitespace(key)); + sb.append(value == null ? StringPool.EMPTY : value); + cursor = end + 1; + } + sb.append(message.substring(cursor)); + return sb.toString(); + } + + /** + * 鍚� log 鏍煎紡鐨� format 瑙勫垯 + * <p> + * use: format("my name is {}, and i like {}!", "L.cm", "Java") + * + * @param message 闇�瑕佽浆鎹㈢殑瀛楃涓� + * @param arguments 闇�瑕佹浛鎹㈢殑鍙橀噺 + * @return 杞崲鍚庣殑瀛楃涓� + */ + public static String format(@Nullable String message, @Nullable Object... arguments) { + // message 涓� null 杩斿洖绌哄瓧绗︿覆 + if (message == null) { + return StringPool.EMPTY; + } + // 鍙傛暟涓� null 鎴栬�呬负绌� + if (arguments == null || arguments.length == 0) { + return message; + } + StringBuilder sb = new StringBuilder((int) (message.length() * 1.5)); + int cursor = 0; + int index = 0; + int argsLength = arguments.length; + for (int start, end; (start = message.indexOf('{', cursor)) != -1 && (end = message.indexOf('}', start)) != -1 && index < argsLength; ) { + sb.append(message, cursor, start); + sb.append(arguments[index]); + cursor = end + 1; + index++; + } + sb.append(message.substring(cursor)); + return sb.toString(); + } + + /** + * 鏍煎紡鍖栨墽琛屾椂闂达紝鍗曚綅涓� ms 鍜� s锛屼繚鐣欎笁浣嶅皬鏁� + * + * @param nanos 绾崇 + * @return 鏍煎紡鍖栧悗鐨勬椂闂� + */ + public static String format(long nanos) { + if (nanos < 1) { + return "0ms"; + } + double millis = (double) nanos / (1000 * 1000); + // 涓嶅 1 ms锛屾渶灏忓崟浣嶄负 ms + if (millis > 1000) { + return String.format("%.3fs", millis / 1000); + } else { + return String.format("%.3fms", millis); + } + } + + /** + * Convert a {@code Collection} into a delimited {@code String} (e.g., CSV). + * <p>Useful for {@code toString()} implementations. + * + * @param coll the {@code Collection} to convert + * @return the delimited {@code String} + */ + public static String join(Collection<?> coll) { + return StringUtil.collectionToCommaDelimitedString(coll); + } + + /** + * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV). + * <p>Useful for {@code toString()} implementations. + * + * @param coll the {@code Collection} to convert + * @param delim the delimiter to use (typically a ",") + * @return the delimited {@code String} + */ + public static String join(Collection<?> coll, String delim) { + return StringUtil.collectionToDelimitedString(coll, delim); + } + + /** + * Convert a {@code String} array into a comma delimited {@code String} + * (i.e., CSV). + * <p>Useful for {@code toString()} implementations. + * + * @param arr the array to display + * @return the delimited {@code String} + */ + public static String join(Object[] arr) { + return StringUtil.arrayToCommaDelimitedString(arr); + } + + /** + * Convert a {@code String} array into a delimited {@code String} (e.g. CSV). + * <p>Useful for {@code toString()} implementations. + * + * @param arr the array to display + * @param delim the delimiter to use (typically a ",") + * @return the delimited {@code String} + */ + public static String join(Object[] arr, String delim) { + return StringUtil.arrayToDelimitedString(arr, delim); + } + + /** + * 瀛楃涓叉槸鍚︾鍚堟寚瀹氱殑 琛ㄨ揪寮� + * + * <p> + * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" + * </p> + * + * @param pattern 琛ㄨ揪寮� + * @param str 瀛楃涓� + * @return 鏄惁鍖归厤 + */ + public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) { + return PatternMatchUtils.simpleMatch(pattern, str); + } + + /** + * 瀛楃涓叉槸鍚︾鍚堟寚瀹氱殑 琛ㄨ揪寮� + * + * <p> + * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" + * </p> + * + * @param patterns 琛ㄨ揪寮� 鏁扮粍 + * @param str 瀛楃涓� + * @return 鏄惁鍖归厤 + */ + public static boolean simpleMatch(@Nullable String[] patterns, String str) { + return PatternMatchUtils.simpleMatch(patterns, str); + } + + /** + * 鐢熸垚uuid + * + * @return UUID + */ + public static String randomUUID() { + ThreadLocalRandom random = ThreadLocalRandom.current(); + return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY); + } + + /** + * 杞箟HTML鐢ㄤ簬瀹夊叏杩囨护 + * + * @param html html + * @return {String} + */ + public static String escapeHtml(String html) { + return StringUtil.isBlank(html) ? StringPool.EMPTY : HtmlUtils.htmlEscape(html); + } + + /** + * 娓呯悊瀛楃涓诧紝娓呯悊鍑烘煇浜涗笉鍙瀛楃 + * + * @param txt 瀛楃涓� + * @return {String} + */ + public static String cleanChars(String txt) { + return txt.replaceAll("[ 銆�`路鈥拷\\f\\t\\v\\s]", ""); + } + + /** + * 鐗规畩瀛楃姝e垯锛宻ql鐗规畩瀛楃鍜岀┖鐧界 + */ + private final static Pattern SPECIAL_CHARS_REGEX = Pattern.compile("[`'\"|/,;()-+*%#路鈥拷銆�\\s]"); + + /** + * 娓呯悊瀛楃涓诧紝娓呯悊鍑烘煇浜涗笉鍙瀛楃鍜屼竴浜泂ql鐗规畩瀛楃 + * + * @param txt 鏂囨湰 + * @return {String} + */ + @Nullable + public static String cleanText(@Nullable String txt) { + if (txt == null) { + return null; + } + return SPECIAL_CHARS_REGEX.matcher(txt).replaceAll(StringPool.EMPTY); + } + + /** + * 鑾峰彇鏍囪瘑绗︼紝鐢ㄤ簬鍙傛暟娓呯悊 + * + * @param param 鍙傛暟 + * @return 娓呯悊鍚庣殑鏍囪瘑绗� + */ + @Nullable + public static String cleanIdentifier(@Nullable String param) { + if (param == null) { + return null; + } + StringBuilder paramBuilder = new StringBuilder(); + for (int i = 0; i < param.length(); i++) { + char c = param.charAt(i); + if (Character.isJavaIdentifierPart(c)) { + paramBuilder.append(c); + } + } + return paramBuilder.toString(); + } + + /** + * 闅忔満鏁扮敓鎴� + * + * @param count 瀛楃闀垮害 + * @return 闅忔満鏁� + */ + public static String random(int count) { + return StringUtil.random(count, RandomType.ALL); + } + + /** + * 闅忔満鏁扮敓鎴� + * + * @param count 瀛楃闀垮害 + * @param randomType 闅忔満鏁扮被鍒� + * @return 闅忔満鏁� + */ + public static String random(int count, RandomType randomType) { + if (count == 0) { + return StringPool.EMPTY; + } + Assert.isTrue(count > 0, "Requested random string length " + count + " is less than 0."); + final Random random = Holder.SECURE_RANDOM; + char[] buffer = new char[count]; + for (int i = 0; i < count; i++) { + String factor = randomType.getFactor(); + buffer[i] = factor.charAt(random.nextInt(factor.length())); + } + return new String(buffer); + } + + /** + * 鏈夊簭鐨勬牸寮忓寲鏂囨湰锛屼娇鐢▄number}鍋氫负鍗犱綅绗�<br> + * 渚嬶細<br> + * 閫氬父浣跨敤锛歠ormat("this is {0} for {1}", "a", "b") =銆� this is a for b<br> + * + * @param pattern 鏂囨湰鏍煎紡 + * @param arguments 鍙傛暟 + * @return 鏍煎紡鍖栧悗鐨勬枃鏈� + */ + public static String indexedFormat(CharSequence pattern, Object... arguments) { + return MessageFormat.format(pattern.toString(), arguments); + } + + /** + * 鏍煎紡鍖栨枃鏈紝浣跨敤 {varName} 鍗犱綅<br> + * map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=銆� aValue and bValue + * + * @param template 鏂囨湰妯℃澘锛岃鏇挎崲鐨勯儴鍒嗙敤 {key} 琛ㄧず + * @param map 鍙傛暟鍊煎 + * @return 鏍煎紡鍖栧悗鐨勬枃鏈� + */ + public static String format(CharSequence template, Map<?, ?> map) { + if (null == template) { + return null; + } + if (null == map || map.isEmpty()) { + return template.toString(); + } + + String template2 = template.toString(); + for (Map.Entry<?, ?> entry : map.entrySet()) { + template2 = template2.replace("{" + entry.getKey() + "}", Func.toStr(entry.getValue())); + } + return template2; + } + + /** + * 鍒囧垎瀛楃涓诧紝涓嶅幓闄ゅ垏鍒嗗悗姣忎釜鍏冪礌涓よ竟鐨勭┖鐧界锛屼笉鍘婚櫎绌虹櫧椤� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @param limit 闄愬埗鍒嗙墖鏁帮紝-1涓嶉檺鍒� + * @return 鍒囧垎鍚庣殑闆嗗悎 + */ + public static List<String> split(CharSequence str, char separator, int limit) { + return split(str, separator, limit, false, false); + } + + /** + * 鍒嗗壊 瀛楃涓� 鍒犻櫎甯歌 绌虹櫧绗� + * + * @param str 瀛楃涓� + * @param delimiter 鍒嗗壊绗� + * @return 瀛楃涓叉暟缁� + */ + public static String[] splitTrim(@Nullable String str, @Nullable String delimiter) { + return StringUtil.delimitedListToStringArray(str, delimiter, " \t\n\n\f"); + } + + /** + * 鍒囧垎瀛楃涓诧紝鍘婚櫎鍒囧垎鍚庢瘡涓厓绱犱袱杈圭殑绌虹櫧绗︼紝鍘婚櫎绌虹櫧椤� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @return 鍒囧垎鍚庣殑闆嗗悎 + * @since 3.1.2 + */ + public static List<String> splitTrim(CharSequence str, char separator) { + return splitTrim(str, separator, -1); + } + + /** + * 鍒囧垎瀛楃涓诧紝鍘婚櫎鍒囧垎鍚庢瘡涓厓绱犱袱杈圭殑绌虹櫧绗︼紝鍘婚櫎绌虹櫧椤� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @return 鍒囧垎鍚庣殑闆嗗悎 + * @since 3.2.0 + */ + public static List<String> splitTrim(CharSequence str, CharSequence separator) { + return splitTrim(str, separator, -1); + } + + /** + * 鍒囧垎瀛楃涓诧紝鍘婚櫎鍒囧垎鍚庢瘡涓厓绱犱袱杈圭殑绌虹櫧绗︼紝鍘婚櫎绌虹櫧椤� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @param limit 闄愬埗鍒嗙墖鏁帮紝-1涓嶉檺鍒� + * @return 鍒囧垎鍚庣殑闆嗗悎 + * @since 3.1.0 + */ + public static List<String> splitTrim(CharSequence str, char separator, int limit) { + return split(str, separator, limit, true, true); + } + + /** + * 鍒囧垎瀛楃涓诧紝鍘婚櫎鍒囧垎鍚庢瘡涓厓绱犱袱杈圭殑绌虹櫧绗︼紝鍘婚櫎绌虹櫧椤� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @param limit 闄愬埗鍒嗙墖鏁帮紝-1涓嶉檺鍒� + * @return 鍒囧垎鍚庣殑闆嗗悎 + * @since 3.2.0 + */ + public static List<String> splitTrim(CharSequence str, CharSequence separator, int limit) { + return split(str, separator, limit, true, true); + } + + /** + * 鍒囧垎瀛楃涓诧紝涓嶉檺鍒跺垎鐗囨暟閲� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @param isTrim 鏄惁鍘婚櫎鍒囧垎瀛楃涓插悗姣忎釜鍏冪礌涓よ竟鐨勭┖鏍� + * @param ignoreEmpty 鏄惁蹇界暐绌轰覆 + * @return 鍒囧垎鍚庣殑闆嗗悎 + * @since 3.0.8 + */ + public static List<String> split(CharSequence str, char separator, boolean isTrim, boolean ignoreEmpty) { + return split(str, separator, 0, isTrim, ignoreEmpty); + } + + /** + * 鍒囧垎瀛楃涓� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @param limit 闄愬埗鍒嗙墖鏁帮紝-1涓嶉檺鍒� + * @param isTrim 鏄惁鍘婚櫎鍒囧垎瀛楃涓插悗姣忎釜鍏冪礌涓よ竟鐨勭┖鏍� + * @param ignoreEmpty 鏄惁蹇界暐绌轰覆 + * @return 鍒囧垎鍚庣殑闆嗗悎 + * @since 3.0.8 + */ + public static List<String> split(CharSequence str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) { + if (null == str) { + return new ArrayList<>(0); + } + return StrSpliter.split(str.toString(), separator, limit, isTrim, ignoreEmpty); + } + + /** + * 鍒囧垎瀛楃涓� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗﹀瓧绗� + * @param limit 闄愬埗鍒嗙墖鏁帮紝-1涓嶉檺鍒� + * @param isTrim 鏄惁鍘婚櫎鍒囧垎瀛楃涓插悗姣忎釜鍏冪礌涓よ竟鐨勭┖鏍� + * @param ignoreEmpty 鏄惁蹇界暐绌轰覆 + * @return 鍒囧垎鍚庣殑闆嗗悎 + * @since 3.2.0 + */ + public static List<String> split(CharSequence str, CharSequence separator, int limit, boolean isTrim, boolean ignoreEmpty) { + if (null == str) { + return new ArrayList<>(0); + } + final String separatorStr = (null == separator) ? null : separator.toString(); + return StrSpliter.split(str.toString(), separatorStr, limit, isTrim, ignoreEmpty); + } + + /** + * 鍒囧垎瀛楃涓� + * + * @param str 琚垏鍒嗙殑瀛楃涓� + * @param separator 鍒嗛殧绗� + * @return 瀛楃涓� + */ + public static String[] split(CharSequence str, CharSequence separator) { + if (str == null) { + return new String[]{}; + } + + final String separatorStr = (null == separator) ? null : separator.toString(); + return StrSpliter.splitToArray(str.toString(), separatorStr, 0, false, false); + } + + /** + * 鏍规嵁缁欏畾闀垮害锛屽皢缁欏畾瀛楃涓叉埅鍙栦负澶氫釜閮ㄥ垎 + * + * @param str 瀛楃涓� + * @param len 姣忎竴涓皬鑺傜殑闀垮害 + * @return 鎴彇鍚庣殑瀛楃涓叉暟缁� + * @see StrSpliter#splitByLength(String, int) + */ + public static String[] split(CharSequence str, int len) { + if (null == str) { + return new String[]{}; + } + return StrSpliter.splitByLength(str.toString(), len); + } + + /** + * 鎸囧畾瀛楃鏄惁鍦ㄥ瓧绗︿覆涓嚭鐜拌繃 + * + * @param str 瀛楃涓� + * @param searchChar 琚煡鎵剧殑瀛楃 + * @return 鏄惁鍖呭惈 + * @since 3.1.2 + */ + public static boolean contains(CharSequence str, char searchChar) { + return indexOf(str, searchChar) > -1; + } + + /** + * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀寘鍚寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆 + * + * @param str 鎸囧畾瀛楃涓� + * @param testStrs 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁� + * @return 鏄惁鍖呭惈浠绘剰涓�涓瓧绗︿覆 + * @since 3.2.0 + */ + public static boolean containsAny(CharSequence str, CharSequence... testStrs) { + return null != getContainsStr(str, testStrs); + } + + /** + * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀寘鍚寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆锛屽鏋滃寘鍚繑鍥炴壘鍒扮殑绗竴涓瓧绗︿覆 + * + * @param str 鎸囧畾瀛楃涓� + * @param testStrs 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁� + * @return 琚寘鍚殑绗竴涓瓧绗︿覆 + * @since 3.2.0 + */ + public static String getContainsStr(CharSequence str, CharSequence... testStrs) { + if (isEmpty(str) || Func.isEmpty(testStrs)) { + return null; + } + for (CharSequence checkStr : testStrs) { + if (str.toString().contains(checkStr)) { + return checkStr.toString(); + } + } + return null; + } + + /** + * 鏄惁鍖呭惈鐗瑰畾瀛楃锛屽拷鐣ュぇ灏忓啓锛屽鏋滅粰瀹氫袱涓弬鏁伴兘涓�<code>null</code>锛岃繑鍥瀟rue + * + * @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鍜宼o浣嶇疆涓�鏍凤紝杩斿洖 "" <br> + * 濡傛灉from鎴杢o涓鸿礋鏁帮紝鍒欐寜鐓ength浠庡悗鍚戝墠鏁颁綅缃紝濡傛灉缁濆鍊煎ぇ浜庡瓧绗︿覆闀垮害锛屽垯from褰掑埌0锛宼o褰掑埌length<br> + * 濡傛灉缁忚繃淇鐨刬ndex涓璮rom澶т簬to锛屽垯浜掓崲from鍜宼o example: <br> + * abcdefgh 2 3 =銆� c <br> + * abcdefgh 2 -3 =銆� cde <br> + * + * @param str String + * @param fromIndex 寮�濮嬬殑index锛堝寘鎷級 + * @param toIndex 缁撴潫鐨刬ndex锛堜笉鍖呮嫭锛� + * @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鎴�""锛夋垨鑰呭垎闅斿瓧绗︿覆涓簄ull锛岃繑鍥炲師瀛楃涓�<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 鏄惁鏌ユ壘鏈�鍚庝竴涓垎闅斿瓧绗︿覆锛堝娆″嚭鐜板垎闅斿瓧绗︿覆鏃堕�夊彇鏈�鍚庝竴涓級锛宼rue涓洪�夊彇鏈�鍚庝竴涓� + * @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> + * 濡傛灉鍒嗛殧瀛楃涓蹭负绌轰覆锛坣ull鎴�""锛夛紝鍒欒繑鍥炵┖涓诧紝濡傛灉鍒嗛殧瀛楃涓叉湭鎵惧埌锛岃繑鍥炵┖涓� + * <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 鏄惁鏌ユ壘鏈�鍚庝竴涓垎闅斿瓧绗︿覆锛堝娆″嚭鐜板垎闅斿瓧绗︿覆鏃堕�夊彇鏈�鍚庝竴涓級锛宼rue涓洪�夊彇鏈�鍚庝竴涓� + * @return 鍒囧壊鍚庣殑瀛楃涓� + * @since 3.1.1 + */ + public static String subAfter(CharSequence string, CharSequence separator, boolean isLastSeparator) { + if (isEmpty(string)) { + return null == string ? null : string.toString(); + } + if (separator == null) { + return StringPool.EMPTY; + } + final String str = string.toString(); + final String sep = separator.toString(); + final int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep); + if (pos == INDEX_NOT_FOUND) { + return StringPool.EMPTY; + } + return str.substring(pos + separator.length()); + } + + /** + * 鎴彇鎸囧畾瀛楃涓蹭腑闂撮儴鍒嗭紝涓嶅寘鎷爣璇嗗瓧绗︿覆<br> + * <p> + * 鏍楀瓙锛� + * + * <pre> + * StringUtil.subBetween("wx[b]yz", "[", "]") = "b" + * StringUtil.subBetween(null, *, *) = null + * StringUtil.subBetween(*, null, *) = null + * StringUtil.subBetween(*, *, null) = null + * StringUtil.subBetween("", "", "") = "" + * StringUtil.subBetween("", "", "]") = null + * StringUtil.subBetween("", "[", "]") = null + * StringUtil.subBetween("yabcz", "", "") = "" + * StringUtil.subBetween("yabcz", "y", "z") = "abc" + * StringUtil.subBetween("yabczyabcz", "y", "z") = "abc" + * </pre> + * + * @param str 琚垏鍓茬殑瀛楃涓� + * @param before 鎴彇寮�濮嬬殑瀛楃涓叉爣璇� + * @param after 鎴彇鍒扮殑瀛楃涓叉爣璇� + * @return 鎴彇鍚庣殑瀛楃涓� + * @since 3.1.1 + */ + public static String subBetween(CharSequence str, CharSequence before, CharSequence after) { + if (str == null || before == null || after == null) { + return null; + } + + final String str2 = str.toString(); + final String before2 = before.toString(); + final String after2 = after.toString(); + + final int start = str2.indexOf(before2); + if (start != INDEX_NOT_FOUND) { + final int end = str2.indexOf(after2, start + before2.length()); + if (end != INDEX_NOT_FOUND) { + return str2.substring(start + before2.length(), end); + } + } + return null; + } + + /** + * 鎴彇鎸囧畾瀛楃涓蹭腑闂撮儴鍒嗭紝涓嶅寘鎷爣璇嗗瓧绗︿覆<br> + * <p> + * 鏍楀瓙锛� + * + * <pre> + * StringUtil.subBetween(null, *) = null + * StringUtil.subBetween("", "") = "" + * StringUtil.subBetween("", "tag") = null + * StringUtil.subBetween("tagabctag", null) = null + * StringUtil.subBetween("tagabctag", "") = "" + * StringUtil.subBetween("tagabctag", "tag") = "abc" + * </pre> + * + * @param str 琚垏鍓茬殑瀛楃涓� + * @param beforeAndAfter 鎴彇寮�濮嬪拰缁撴潫鐨勫瓧绗︿覆鏍囪瘑 + * @return 鎴彇鍚庣殑瀛楃涓� + * @since 3.1.1 + */ + public static String subBetween(CharSequence str, CharSequence beforeAndAfter) { + return subBetween(str, beforeAndAfter, beforeAndAfter); + } + + /** + * 鍘绘帀鎸囧畾鍓嶇紑 + * + * @param str 瀛楃涓� + * @param prefix 鍓嶇紑 + * @return 鍒囨帀鍚庣殑瀛楃涓诧紝鑻ュ墠缂�涓嶆槸 preffix锛� 杩斿洖鍘熷瓧绗︿覆 + */ + public static String removePrefix(CharSequence str, CharSequence prefix) { + if (isEmpty(str) || isEmpty(prefix)) { + return StringPool.EMPTY; + } + + final String str2 = str.toString(); + if (str2.startsWith(prefix.toString())) { + return subSuf(str2, prefix.length()); + } + return str2; + } + + /** + * 蹇界暐澶у皬鍐欏幓鎺夋寚瀹氬墠缂� + * + * @param str 瀛楃涓� + * @param prefix 鍓嶇紑 + * @return 鍒囨帀鍚庣殑瀛楃涓诧紝鑻ュ墠缂�涓嶆槸 prefix锛� 杩斿洖鍘熷瓧绗︿覆 + */ + public static String removePrefixIgnoreCase(CharSequence str, CharSequence prefix) { + if (isEmpty(str) || isEmpty(prefix)) { + return StringPool.EMPTY; + } + + final String str2 = str.toString(); + if (str2.toLowerCase().startsWith(prefix.toString().toLowerCase())) { + return subSuf(str2, prefix.length()); + } + return str2; + } + + /** + * 鍘绘帀鎸囧畾鍚庣紑 + * + * @param str 瀛楃涓� + * @param suffix 鍚庣紑 + * @return 鍒囨帀鍚庣殑瀛楃涓诧紝鑻ュ悗缂�涓嶆槸 suffix锛� 杩斿洖鍘熷瓧绗︿覆 + */ + public static String removeSuffix(CharSequence str, CharSequence suffix) { + if (isEmpty(str) || isEmpty(suffix)) { + return StringPool.EMPTY; + } + + final String str2 = str.toString(); + if (str2.endsWith(suffix.toString())) { + return subPre(str2, str2.length() - suffix.length()); + } + return str2; + } + + /** + * 鍘绘帀鎸囧畾鍚庣紑锛屽苟灏忓啓棣栧瓧姣� + * + * @param str 瀛楃涓� + * @param suffix 鍚庣紑 + * @return 鍒囨帀鍚庣殑瀛楃涓诧紝鑻ュ悗缂�涓嶆槸 suffix锛� 杩斿洖鍘熷瓧绗︿覆 + */ + public static String removeSufAndLowerFirst(CharSequence str, CharSequence suffix) { + return firstCharToLower(removeSuffix(str, suffix)); + } + + /** + * 蹇界暐澶у皬鍐欏幓鎺夋寚瀹氬悗缂� + * + * @param str 瀛楃涓� + * @param suffix 鍚庣紑 + * @return 鍒囨帀鍚庣殑瀛楃涓诧紝鑻ュ悗缂�涓嶆槸 suffix锛� 杩斿洖鍘熷瓧绗︿覆 + */ + public static String removeSuffixIgnoreCase(CharSequence str, CharSequence suffix) { + if (isEmpty(str) || isEmpty(suffix)) { + return StringPool.EMPTY; + } + + final String str2 = str.toString(); + if (str2.toLowerCase().endsWith(suffix.toString().toLowerCase())) { + return subPre(str2, str2.length() - suffix.length()); + } + return str2; + } + + /** + * 棣栧瓧姣嶅彉灏忓啓 + * + * @param str 瀛楃涓� + * @return {String} + */ + public static String firstCharToLower(String str) { + char firstChar = str.charAt(0); + if (firstChar >= CharPool.UPPER_A && firstChar <= CharPool.UPPER_Z) { + char[] arr = str.toCharArray(); + arr[0] += (CharPool.LOWER_A - CharPool.UPPER_A); + return new String(arr); + } + return str; + } + + /** + * 棣栧瓧姣嶅彉澶у啓 + * + * @param str 瀛楃涓� + * @return {String} + */ + public static String firstCharToUpper(String str) { + char firstChar = str.charAt(0); + if (firstChar >= CharPool.LOWER_A && firstChar <= CharPool.LOWER_Z) { + char[] arr = str.toCharArray(); + arr[0] -= (CharPool.LOWER_A - CharPool.UPPER_A); + return new String(arr); + } + return str; + } + + /** + * 鍒囧壊鎸囧畾浣嶇疆涔嬪墠閮ㄥ垎鐨勫瓧绗︿覆 + * + * @param string 瀛楃涓� + * @param toIndex 鍒囧壊鍒扮殑浣嶇疆锛堜笉鍖呮嫭锛� + * @return 鍒囧壊鍚庣殑鍓╀綑鐨勫墠鍗婇儴鍒嗗瓧绗︿覆 + */ + public static String subPre(CharSequence string, int toIndex) { + return sub(string, 0, toIndex); + } + + /** + * 鍒囧壊鎸囧畾浣嶇疆涔嬪悗閮ㄥ垎鐨勫瓧绗︿覆 + * + * @param string 瀛楃涓� + * @param fromIndex 鍒囧壊寮�濮嬬殑浣嶇疆锛堝寘鎷級 + * @return 鍒囧壊鍚庡悗鍓╀綑鐨勫悗鍗婇儴鍒嗗瓧绗︿覆 + */ + public static String subSuf(CharSequence string, int fromIndex) { + if (isEmpty(string)) { + return null; + } + return sub(string, fromIndex, string.length()); + } + + /** + * 鎸囧畾鑼冨洿鍐呮煡鎵炬寚瀹氬瓧绗� + * + * @param str 瀛楃涓� + * @param searchChar 琚煡鎵剧殑瀛楃 + * @return 浣嶇疆 + */ + public static int indexOf(final CharSequence str, char searchChar) { + return indexOf(str, searchChar, 0); + } + + /** + * 鎸囧畾鑼冨洿鍐呮煡鎵炬寚瀹氬瓧绗� + * + * @param str 瀛楃涓� + * @param searchChar 琚煡鎵剧殑瀛楃 + * @param start 璧峰浣嶇疆锛屽鏋滃皬浜�0锛屼粠0寮�濮嬫煡鎵� + * @return 浣嶇疆 + */ + public static int indexOf(final CharSequence str, char searchChar, int start) { + if (str instanceof String) { + return ((String) str).indexOf(searchChar, start); + } else { + return indexOf(str, searchChar, start, -1); + } + } + + /** + * 鎸囧畾鑼冨洿鍐呮煡鎵炬寚瀹氬瓧绗� + * + * @param str 瀛楃涓� + * @param searchChar 琚煡鎵剧殑瀛楃 + * @param start 璧峰浣嶇疆锛屽鏋滃皬浜�0锛屼粠0寮�濮嬫煡鎵� + * @param end 缁堟浣嶇疆锛屽鏋滆秴杩噑tr.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> + * 鏍楀瓙锛�*浠h〃浠绘剰瀛楃锛夛細 + * + * <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 琚鏌ョ殑瀛楃涓诧紝鍙互涓簄ull + * @param searchStr 琚煡鎵剧殑瀛楃涓诧紝鍙互涓簄ull + * @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> + * 浠绘剰涓�涓瓧绗︿覆涓簄ull杩斿洖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闈炵┖锛岀洿鎺alse + return false; + } + + if (ignoreCase) { + return str1.toString().equalsIgnoreCase(str2.toString()); + } else { + return str1.equals(str2); + } + } + + /** + * 鍒涘缓StringBuilder瀵硅薄 + * + * @return {String}Builder瀵硅薄 + */ + public static StringBuilder builder() { + return new StringBuilder(); + } + + /** + * 鍒涘缓StringBuilder瀵硅薄 + * + * @param capacity 鍒濆澶у皬 + * @return {String}Builder瀵硅薄 + */ + public static StringBuilder builder(int capacity) { + return new StringBuilder(capacity); + } + + /** + * 鍒涘缓StringBuilder瀵硅薄 + * + * @param strs 鍒濆瀛楃涓插垪琛� + * @return {String}Builder瀵硅薄 + */ + public static StringBuilder builder(CharSequence... strs) { + final StringBuilder sb = new StringBuilder(); + for (CharSequence str : strs) { + sb.append(str); + } + return sb; + } + + /** + * 鍒涘缓StringBuilder瀵硅薄 + * + * @param sb 鍒濆StringBuilder + * @param strs 鍒濆瀛楃涓插垪琛� + * @return {String}Builder瀵硅薄 + */ + public static StringBuilder appendBuilder(StringBuilder sb, CharSequence... strs) { + for (CharSequence str : strs) { + sb.append(str); + } + return sb; + } + + /** + * 鑾峰緱StringReader + * + * @param str 瀛楃涓� + * @return {String}Reader + */ + public static StringReader getReader(CharSequence str) { + if (null == str) { + return null; + } + return new StringReader(str.toString()); + } + + /** + * 鑾峰緱StringWriter + * + * @return {String}Writer + */ + public static StringWriter getWriter() { + return new StringWriter(); + } + + /** + * 缁熻鎸囧畾鍐呭涓寘鍚寚瀹氬瓧绗︿覆鐨勬暟閲�<br> + * 鍙傛暟涓� {@code null} 鎴栬�� "" 杩斿洖 {@code 0}. + * + * <pre> + * StringUtil.count(null, *) = 0 + * StringUtil.count("", *) = 0 + * StringUtil.count("abba", null) = 0 + * StringUtil.count("abba", "") = 0 + * StringUtil.count("abba", "a") = 2 + * StringUtil.count("abba", "ab") = 1 + * StringUtil.count("abba", "xxx") = 0 + * </pre> + * + * @param content 琚煡鎵剧殑瀛楃涓� + * @param strForSearch 闇�瑕佹煡鎵剧殑瀛楃涓� + * @return 鏌ユ壘鍒扮殑涓暟 + */ + public static int count(CharSequence content, CharSequence strForSearch) { + if (Func.hasEmpty(content, strForSearch) || strForSearch.length() > content.length()) { + return 0; + } + + int count = 0; + int idx = 0; + final String content2 = content.toString(); + final String strForSearch2 = strForSearch.toString(); + while ((idx = content2.indexOf(strForSearch2, idx)) > -1) { + count++; + idx += strForSearch.length(); + } + return count; + } + + /** + * 缁熻鎸囧畾鍐呭涓寘鍚寚瀹氬瓧绗︾殑鏁伴噺 + * + * @param content 鍐呭 + * @param charForSearch 琚粺璁$殑瀛楃 + * @return 鍖呭惈鏁伴噺 + */ + public static int count(CharSequence content, char charForSearch) { + int count = 0; + if (isEmpty(content)) { + return 0; + } + int contentLength = content.length(); + for (int i = 0; i < contentLength; i++) { + if (charForSearch == content.charAt(i)) { + count++; + } + } + return count; + } + + /** + * 涓嬪垝绾胯浆椹煎嘲 + * + * @param para 瀛楃涓� + * @return {String} + */ + public static String underlineToHump(String para) { + if (isBlank(para)) { + return StringPool.EMPTY; + } + StringBuilder result = new StringBuilder(); + String[] a = para.split("_"); + for (String s : a) { + if (result.length() == 0) { + result.append(s.toLowerCase()); + } else { + result.append(s.substring(0, 1).toUpperCase()); + result.append(s.substring(1).toLowerCase()); + } + } + return result.toString(); + } + + /** + * 椹煎嘲杞笅鍒掔嚎 + * + * @param para 瀛楃涓� + * @return {String} + */ + public static String humpToUnderline(String para) { + if (isBlank(para)) { + return StringPool.EMPTY; + } + para = firstCharToLower(para); + StringBuilder sb = new StringBuilder(para); + int temp = 0; + for (int i = 0; i < para.length(); i++) { + if (Character.isUpperCase(para.charAt(i))) { + sb.insert(i + temp, "_"); + temp += 1; + } + } + return sb.toString().toLowerCase(); + } + + /** + * 妯嚎杞┘宄� + * + * @param para 瀛楃涓� + * @return {String} + */ + public static String lineToHump(String para) { + if (isBlank(para)) { + return StringPool.EMPTY; + } + StringBuilder result = new StringBuilder(); + String[] a = para.split("-"); + for (String s : a) { + if (result.length() == 0) { + result.append(s.toLowerCase()); + } else { + result.append(s.substring(0, 1).toUpperCase()); + result.append(s.substring(1).toLowerCase()); + } + } + return result.toString(); + } + + /** + * 椹煎嘲杞í绾� + * + * @param para 瀛楃涓� + * @return {String} + */ + public static String humpToLine(String para) { + if (isBlank(para)) { + return StringPool.EMPTY; + } + para = firstCharToLower(para); + StringBuilder sb = new StringBuilder(para); + int temp = 0; + for (int i = 0; i < para.length(); i++) { + if (Character.isUpperCase(para.charAt(i))) { + sb.insert(i + temp, "-"); + temp += 1; + } + } + return sb.toString().toLowerCase(); + } + + +} + -- Gitblit v1.9.3