¶Ô±ÈÐÂÎļþ |
| | |
| | | /* |
| | | * Copyright (c) 2018-2028, DreamLu All rights reserved. |
| | | * |
| | | * Redistribution and use in source and binary forms, with or without |
| | | * modification, are permitted provided that the following conditions are met: |
| | | * |
| | | * Redistributions of source code must retain the above copyright notice, |
| | | * this list of conditions and the following disclaimer. |
| | | * Redistributions in binary form must reproduce the above copyright |
| | | * notice, this list of conditions and the following disclaimer in the |
| | | * documentation and/or other materials provided with the distribution. |
| | | * Neither the name of the dreamlu.net developer nor the names of its |
| | | * contributors may be used to endorse or promote products derived from |
| | | * this software without specific prior written permission. |
| | | * Author: DreamLu 墿¥æ¢¦ (596392912@qq.com) |
| | | */ |
| | | package org.springblade.core.tool.utils; |
| | | |
| | | import org.springblade.core.tool.support.StrSpliter; |
| | | import org.springframework.lang.Nullable; |
| | | import org.springframework.util.Assert; |
| | | import org.springframework.util.PatternMatchUtils; |
| | | import org.springframework.web.util.HtmlUtils; |
| | | |
| | | import java.io.StringReader; |
| | | import java.io.StringWriter; |
| | | import java.text.MessageFormat; |
| | | import java.util.*; |
| | | import java.util.concurrent.ThreadLocalRandom; |
| | | import java.util.regex.Pattern; |
| | | import java.util.stream.Stream; |
| | | |
| | | /** |
| | | * ç»§æ¿èªSpring utilçå·¥å
·ç±»ï¼åå°jarä¾èµ |
| | | * |
| | | * @author L.cm |
| | | */ |
| | | public class StringUtil extends org.springframework.util.StringUtils { |
| | | |
| | | public static final int INDEX_NOT_FOUND = -1; |
| | | |
| | | /** |
| | | * Check whether the given {@code CharSequence} contains actual <em>text</em>. |
| | | * <p>More specifically, this method returns {@code true} if the |
| | | * {@code CharSequence} is not {@code null}, its length is greater than |
| | | * 0, and it contains at least one non-whitespace character. |
| | | * <pre class="code"> |
| | | * StringUtil.isBlank(null) = true |
| | | * StringUtil.isBlank("") = true |
| | | * StringUtil.isBlank(" ") = true |
| | | * StringUtil.isBlank("12345") = false |
| | | * StringUtil.isBlank(" 12345 ") = false |
| | | * </pre> |
| | | * |
| | | * @param cs the {@code CharSequence} to check (may be {@code null}) |
| | | * @return {@code true} if the {@code CharSequence} is not {@code null}, |
| | | * its length is greater than 0, and it does not contain whitespace only |
| | | * @see Character#isWhitespace |
| | | */ |
| | | public static boolean isBlank(final CharSequence cs) { |
| | | return !StringUtil.hasText(cs); |
| | | } |
| | | |
| | | /** |
| | | * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> |
| | | * <pre> |
| | | * StringUtil.isNotBlank(null) = false |
| | | * StringUtil.isNotBlank("") = false |
| | | * StringUtil.isNotBlank(" ") = false |
| | | * StringUtil.isNotBlank("bob") = true |
| | | * StringUtil.isNotBlank(" bob ") = true |
| | | * </pre> |
| | | * |
| | | * @param cs the CharSequence to check, may be null |
| | | * @return {@code true} if the CharSequence is |
| | | * not empty and not null and not whitespace |
| | | * @see Character#isWhitespace |
| | | */ |
| | | public static boolean isNotBlank(final CharSequence cs) { |
| | | return StringUtil.hasText(cs); |
| | | } |
| | | |
| | | /** |
| | | * æ ä»»æ ä¸ä¸ª Blank |
| | | * |
| | | * @param css CharSequence |
| | | * @return boolean |
| | | */ |
| | | public static boolean isAnyBlank(final CharSequence... css) { |
| | | if (ObjectUtil.isEmpty(css)) { |
| | | return true; |
| | | } |
| | | return Stream.of(css).anyMatch(StringUtil::isBlank); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦å
¨é Blank |
| | | * |
| | | * @param css CharSequence |
| | | * @return boolean |
| | | */ |
| | | public static boolean isNoneBlank(final CharSequence... css) { |
| | | if (ObjectUtil.isEmpty(css)) { |
| | | return false; |
| | | } |
| | | return Stream.of(css).allMatch(StringUtil::isNotBlank); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦å
¨ä¸º Blank |
| | | * |
| | | * @param css CharSequence |
| | | * @return boolean |
| | | */ |
| | | public static boolean isAllBlank(final CharSequence... css) { |
| | | return Stream.of(css).allMatch(StringUtil::isBlank); |
| | | } |
| | | |
| | | /** |
| | | * 夿ä¸ä¸ªå符串æ¯å¦æ¯æ°å |
| | | * |
| | | * @param cs the CharSequence to check, may be null |
| | | * @return {boolean} |
| | | */ |
| | | public static boolean isNumeric(final CharSequence cs) { |
| | | if (isBlank(cs)) { |
| | | return false; |
| | | } |
| | | for (int i = cs.length(); --i >= 0; ) { |
| | | int chr = cs.charAt(i); |
| | | if (chr < 48 || chr > 57) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * å°å符串ä¸ç¹å®æ¨¡å¼çåç¬¦è½¬æ¢æmapä¸å¯¹åºçå¼ |
| | | * <p> |
| | | * use: format("my name is ${name}, and i like ${like}!", {"name":"L.cm", "like": "Java"}) |
| | | * |
| | | * @param message éè¦è½¬æ¢çå符串 |
| | | * @param params è½¬æ¢æéçé®å¼å¯¹éå |
| | | * @return 转æ¢åçå符串 |
| | | */ |
| | | public static String format(@Nullable String message, @Nullable Map<String, ?> params) { |
| | | // message 为 null è¿å空å符串 |
| | | if (message == null) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | // åæ°ä¸º null æè
为空 |
| | | if (params == null || params.isEmpty()) { |
| | | return message; |
| | | } |
| | | // æ¿æ¢åé |
| | | StringBuilder sb = new StringBuilder((int) (message.length() * 1.5)); |
| | | int cursor = 0; |
| | | for (int start, end; (start = message.indexOf(StringPool.DOLLAR_LEFT_BRACE, cursor)) != -1 && (end = message.indexOf(StringPool.RIGHT_BRACE, start)) != -1; ) { |
| | | sb.append(message, cursor, start); |
| | | String key = message.substring(start + 2, end); |
| | | Object value = params.get(StringUtil.trimWhitespace(key)); |
| | | sb.append(value == null ? StringPool.EMPTY : value); |
| | | cursor = end + 1; |
| | | } |
| | | sb.append(message.substring(cursor)); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * å log æ ¼å¼ç format è§å |
| | | * <p> |
| | | * use: format("my name is {}, and i like {}!", "L.cm", "Java") |
| | | * |
| | | * @param message éè¦è½¬æ¢çå符串 |
| | | * @param arguments éè¦æ¿æ¢çåé |
| | | * @return 转æ¢åçå符串 |
| | | */ |
| | | public static String format(@Nullable String message, @Nullable Object... arguments) { |
| | | // message 为 null è¿å空å符串 |
| | | if (message == null) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | // åæ°ä¸º null æè
为空 |
| | | if (arguments == null || arguments.length == 0) { |
| | | return message; |
| | | } |
| | | StringBuilder sb = new StringBuilder((int) (message.length() * 1.5)); |
| | | int cursor = 0; |
| | | int index = 0; |
| | | int argsLength = arguments.length; |
| | | for (int start, end; (start = message.indexOf('{', cursor)) != -1 && (end = message.indexOf('}', start)) != -1 && index < argsLength; ) { |
| | | sb.append(message, cursor, start); |
| | | sb.append(arguments[index]); |
| | | cursor = end + 1; |
| | | index++; |
| | | } |
| | | sb.append(message.substring(cursor)); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * æ ¼å¼åæ§è¡æ¶é´ï¼åä½ä¸º ms å sï¼ä¿çä¸ä½å°æ° |
| | | * |
| | | * @param nanos çº³ç§ |
| | | * @return æ ¼å¼ååçæ¶é´ |
| | | */ |
| | | public static String format(long nanos) { |
| | | if (nanos < 1) { |
| | | return "0ms"; |
| | | } |
| | | double millis = (double) nanos / (1000 * 1000); |
| | | // ä¸å¤ 1 msï¼æå°åä½ä¸º ms |
| | | if (millis > 1000) { |
| | | return String.format("%.3fs", millis / 1000); |
| | | } else { |
| | | return String.format("%.3fms", millis); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Convert a {@code Collection} into a delimited {@code String} (e.g., CSV). |
| | | * <p>Useful for {@code toString()} implementations. |
| | | * |
| | | * @param coll the {@code Collection} to convert |
| | | * @return the delimited {@code String} |
| | | */ |
| | | public static String join(Collection<?> coll) { |
| | | return StringUtil.collectionToCommaDelimitedString(coll); |
| | | } |
| | | |
| | | /** |
| | | * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV). |
| | | * <p>Useful for {@code toString()} implementations. |
| | | * |
| | | * @param coll the {@code Collection} to convert |
| | | * @param delim the delimiter to use (typically a ",") |
| | | * @return the delimited {@code String} |
| | | */ |
| | | public static String join(Collection<?> coll, String delim) { |
| | | return StringUtil.collectionToDelimitedString(coll, delim); |
| | | } |
| | | |
| | | /** |
| | | * Convert a {@code String} array into a comma delimited {@code String} |
| | | * (i.e., CSV). |
| | | * <p>Useful for {@code toString()} implementations. |
| | | * |
| | | * @param arr the array to display |
| | | * @return the delimited {@code String} |
| | | */ |
| | | public static String join(Object[] arr) { |
| | | return StringUtil.arrayToCommaDelimitedString(arr); |
| | | } |
| | | |
| | | /** |
| | | * Convert a {@code String} array into a delimited {@code String} (e.g. CSV). |
| | | * <p>Useful for {@code toString()} implementations. |
| | | * |
| | | * @param arr the array to display |
| | | * @param delim the delimiter to use (typically a ",") |
| | | * @return the delimited {@code String} |
| | | */ |
| | | public static String join(Object[] arr, String delim) { |
| | | return StringUtil.arrayToDelimitedString(arr, delim); |
| | | } |
| | | |
| | | /** |
| | | * å符串æ¯å¦ç¬¦åæå®ç è¡¨è¾¾å¼ |
| | | * |
| | | * <p> |
| | | * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" |
| | | * </p> |
| | | * |
| | | * @param pattern è¡¨è¾¾å¼ |
| | | * @param str å符串 |
| | | * @return æ¯å¦å¹é
|
| | | */ |
| | | public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) { |
| | | return PatternMatchUtils.simpleMatch(pattern, str); |
| | | } |
| | | |
| | | /** |
| | | * å符串æ¯å¦ç¬¦åæå®ç è¡¨è¾¾å¼ |
| | | * |
| | | * <p> |
| | | * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" |
| | | * </p> |
| | | * |
| | | * @param patterns è¡¨è¾¾å¼ æ°ç» |
| | | * @param str å符串 |
| | | * @return æ¯å¦å¹é
|
| | | */ |
| | | public static boolean simpleMatch(@Nullable String[] patterns, String str) { |
| | | return PatternMatchUtils.simpleMatch(patterns, str); |
| | | } |
| | | |
| | | /** |
| | | * çæuuid |
| | | * |
| | | * @return UUID |
| | | */ |
| | | public static String randomUUID() { |
| | | ThreadLocalRandom random = ThreadLocalRandom.current(); |
| | | return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY); |
| | | } |
| | | |
| | | /** |
| | | * 转ä¹HTMLç¨äºå®å
¨è¿æ»¤ |
| | | * |
| | | * @param html html |
| | | * @return {String} |
| | | */ |
| | | public static String escapeHtml(String html) { |
| | | return StringUtil.isBlank(html) ? StringPool.EMPTY : HtmlUtils.htmlEscape(html); |
| | | } |
| | | |
| | | /** |
| | | * æ¸
çåç¬¦ä¸²ï¼æ¸
çåºæäºä¸å¯è§å符 |
| | | * |
| | | * @param txt å符串 |
| | | * @return {String} |
| | | */ |
| | | public static String cleanChars(String txt) { |
| | | return txt.replaceAll("[ ã`·â¢ï¿½\\f\\t\\v\\s]", ""); |
| | | } |
| | | |
| | | /** |
| | | * ç¹æ®å符æ£åï¼sqlç¹æ®å符å空ç½ç¬¦ |
| | | */ |
| | | private final static Pattern SPECIAL_CHARS_REGEX = Pattern.compile("[`'\"|/,;()-+*%#·â¢ï¿½ã\\s]"); |
| | | |
| | | /** |
| | | * æ¸
çåç¬¦ä¸²ï¼æ¸
çåºæäºä¸å¯è§å符åä¸äºsqlç¹æ®å符 |
| | | * |
| | | * @param txt ææ¬ |
| | | * @return {String} |
| | | */ |
| | | @Nullable |
| | | public static String cleanText(@Nullable String txt) { |
| | | if (txt == null) { |
| | | return null; |
| | | } |
| | | return SPECIAL_CHARS_REGEX.matcher(txt).replaceAll(StringPool.EMPTY); |
| | | } |
| | | |
| | | /** |
| | | * è·åæ è¯ç¬¦ï¼ç¨äºåæ°æ¸
ç |
| | | * |
| | | * @param param åæ° |
| | | * @return æ¸
çåçæ è¯ç¬¦ |
| | | */ |
| | | @Nullable |
| | | public static String cleanIdentifier(@Nullable String param) { |
| | | if (param == null) { |
| | | return null; |
| | | } |
| | | StringBuilder paramBuilder = new StringBuilder(); |
| | | for (int i = 0; i < param.length(); i++) { |
| | | char c = param.charAt(i); |
| | | if (Character.isJavaIdentifierPart(c)) { |
| | | paramBuilder.append(c); |
| | | } |
| | | } |
| | | return paramBuilder.toString(); |
| | | } |
| | | |
| | | /** |
| | | * éæºæ°çæ |
| | | * |
| | | * @param count å符é¿åº¦ |
| | | * @return éæºæ° |
| | | */ |
| | | public static String random(int count) { |
| | | return StringUtil.random(count, RandomType.ALL); |
| | | } |
| | | |
| | | /** |
| | | * éæºæ°çæ |
| | | * |
| | | * @param count å符é¿åº¦ |
| | | * @param randomType éæºæ°ç±»å« |
| | | * @return éæºæ° |
| | | */ |
| | | public static String random(int count, RandomType randomType) { |
| | | if (count == 0) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | Assert.isTrue(count > 0, "Requested random string length " + count + " is less than 0."); |
| | | final Random random = Holder.SECURE_RANDOM; |
| | | char[] buffer = new char[count]; |
| | | for (int i = 0; i < count; i++) { |
| | | String factor = randomType.getFactor(); |
| | | buffer[i] = factor.charAt(random.nextInt(factor.length())); |
| | | } |
| | | return new String(buffer); |
| | | } |
| | | |
| | | /** |
| | | * æåºçæ ¼å¼åææ¬ï¼ä½¿ç¨{number}å为å ä½ç¬¦<br> |
| | | * ä¾ï¼<br> |
| | | * é常使ç¨ï¼format("this is {0} for {1}", "a", "b") =ã this is a for b<br> |
| | | * |
| | | * @param pattern ææ¬æ ¼å¼ |
| | | * @param arguments åæ° |
| | | * @return æ ¼å¼ååçææ¬ |
| | | */ |
| | | public static String indexedFormat(CharSequence pattern, Object... arguments) { |
| | | return MessageFormat.format(pattern.toString(), arguments); |
| | | } |
| | | |
| | | /** |
| | | * æ ¼å¼åææ¬ï¼ä½¿ç¨ {varName} å ä½<br> |
| | | * map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=ã aValue and bValue |
| | | * |
| | | * @param template ææ¬æ¨¡æ¿ï¼è¢«æ¿æ¢çé¨åç¨ {key} 表示 |
| | | * @param map åæ°å¼å¯¹ |
| | | * @return æ ¼å¼ååçææ¬ |
| | | */ |
| | | public static String format(CharSequence template, Map<?, ?> map) { |
| | | if (null == template) { |
| | | return null; |
| | | } |
| | | if (null == map || map.isEmpty()) { |
| | | return template.toString(); |
| | | } |
| | | |
| | | String template2 = template.toString(); |
| | | for (Map.Entry<?, ?> entry : map.entrySet()) { |
| | | template2 = template2.replace("{" + entry.getKey() + "}", Func.toStr(entry.getValue())); |
| | | } |
| | | return template2; |
| | | } |
| | | |
| | | /** |
| | | * ååå符串ï¼ä¸å»é¤åååæ¯ä¸ªå
ç´ ä¸¤è¾¹ç空ç½ç¬¦ï¼ä¸å»é¤ç©ºç½é¡¹ |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @param limit éå¶åçæ°ï¼-1ä¸éå¶ |
| | | * @return åååçéå |
| | | */ |
| | | public static List<String> split(CharSequence str, char separator, int limit) { |
| | | return split(str, separator, limit, false, false); |
| | | } |
| | | |
| | | /** |
| | | * åå² å符串 å é¤å¸¸è§ 空ç½ç¬¦ |
| | | * |
| | | * @param str å符串 |
| | | * @param delimiter åå²ç¬¦ |
| | | * @return å符串æ°ç» |
| | | */ |
| | | public static String[] splitTrim(@Nullable String str, @Nullable String delimiter) { |
| | | return StringUtil.delimitedListToStringArray(str, delimiter, " \t\n\n\f"); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串ï¼å»é¤åååæ¯ä¸ªå
ç´ ä¸¤è¾¹ç空ç½ç¬¦ï¼å»é¤ç©ºç½é¡¹ |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @return åååçéå |
| | | * @since 3.1.2 |
| | | */ |
| | | public static List<String> splitTrim(CharSequence str, char separator) { |
| | | return splitTrim(str, separator, -1); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串ï¼å»é¤åååæ¯ä¸ªå
ç´ ä¸¤è¾¹ç空ç½ç¬¦ï¼å»é¤ç©ºç½é¡¹ |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @return åååçéå |
| | | * @since 3.2.0 |
| | | */ |
| | | public static List<String> splitTrim(CharSequence str, CharSequence separator) { |
| | | return splitTrim(str, separator, -1); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串ï¼å»é¤åååæ¯ä¸ªå
ç´ ä¸¤è¾¹ç空ç½ç¬¦ï¼å»é¤ç©ºç½é¡¹ |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @param limit éå¶åçæ°ï¼-1ä¸éå¶ |
| | | * @return åååçéå |
| | | * @since 3.1.0 |
| | | */ |
| | | public static List<String> splitTrim(CharSequence str, char separator, int limit) { |
| | | return split(str, separator, limit, true, true); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串ï¼å»é¤åååæ¯ä¸ªå
ç´ ä¸¤è¾¹ç空ç½ç¬¦ï¼å»é¤ç©ºç½é¡¹ |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @param limit éå¶åçæ°ï¼-1ä¸éå¶ |
| | | * @return åååçéå |
| | | * @since 3.2.0 |
| | | */ |
| | | public static List<String> splitTrim(CharSequence str, CharSequence separator, int limit) { |
| | | return split(str, separator, limit, true, true); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串ï¼ä¸éå¶åçæ°é |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @param isTrim æ¯å¦å»é¤åååç¬¦ä¸²åæ¯ä¸ªå
ç´ ä¸¤è¾¹çç©ºæ ¼ |
| | | * @param ignoreEmpty æ¯å¦å¿½ç¥ç©ºä¸² |
| | | * @return åååçéå |
| | | * @since 3.0.8 |
| | | */ |
| | | public static List<String> split(CharSequence str, char separator, boolean isTrim, boolean ignoreEmpty) { |
| | | return split(str, separator, 0, isTrim, ignoreEmpty); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串 |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @param limit éå¶åçæ°ï¼-1ä¸éå¶ |
| | | * @param isTrim æ¯å¦å»é¤åååç¬¦ä¸²åæ¯ä¸ªå
ç´ ä¸¤è¾¹çç©ºæ ¼ |
| | | * @param ignoreEmpty æ¯å¦å¿½ç¥ç©ºä¸² |
| | | * @return åååçéå |
| | | * @since 3.0.8 |
| | | */ |
| | | public static List<String> split(CharSequence str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) { |
| | | if (null == str) { |
| | | return new ArrayList<>(0); |
| | | } |
| | | return StrSpliter.split(str.toString(), separator, limit, isTrim, ignoreEmpty); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串 |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符å符 |
| | | * @param limit éå¶åçæ°ï¼-1ä¸éå¶ |
| | | * @param isTrim æ¯å¦å»é¤åååç¬¦ä¸²åæ¯ä¸ªå
ç´ ä¸¤è¾¹çç©ºæ ¼ |
| | | * @param ignoreEmpty æ¯å¦å¿½ç¥ç©ºä¸² |
| | | * @return åååçéå |
| | | * @since 3.2.0 |
| | | */ |
| | | public static List<String> split(CharSequence str, CharSequence separator, int limit, boolean isTrim, boolean ignoreEmpty) { |
| | | if (null == str) { |
| | | return new ArrayList<>(0); |
| | | } |
| | | final String separatorStr = (null == separator) ? null : separator.toString(); |
| | | return StrSpliter.split(str.toString(), separatorStr, limit, isTrim, ignoreEmpty); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串 |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符 |
| | | * @return å符串 |
| | | */ |
| | | public static String[] split(CharSequence str, CharSequence separator) { |
| | | if (str == null) { |
| | | return new String[]{}; |
| | | } |
| | | |
| | | final String separatorStr = (null == separator) ? null : separator.toString(); |
| | | return StrSpliter.splitToArray(str.toString(), separatorStr, 0, false, false); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®ç»å®é¿åº¦ï¼å°ç»å®å符串æªå为å¤ä¸ªé¨å |
| | | * |
| | | * @param str å符串 |
| | | * @param len æ¯ä¸ä¸ªå°èçé¿åº¦ |
| | | * @return æªååçå符串æ°ç» |
| | | * @see StrSpliter#splitByLength(String, int) |
| | | */ |
| | | public static String[] split(CharSequence str, int len) { |
| | | if (null == str) { |
| | | return new String[]{}; |
| | | } |
| | | return StrSpliter.splitByLength(str.toString(), len); |
| | | } |
| | | |
| | | /** |
| | | * æå®å符æ¯å¦å¨å符串ä¸åºç°è¿ |
| | | * |
| | | * @param str å符串 |
| | | * @param searchChar è¢«æ¥æ¾çå符 |
| | | * @return æ¯å¦å
å« |
| | | * @since 3.1.2 |
| | | */ |
| | | public static boolean contains(CharSequence str, char searchChar) { |
| | | return indexOf(str, searchChar) > -1; |
| | | } |
| | | |
| | | /** |
| | | * æ¥æ¾æå®å符串æ¯å¦å
嫿å®å符串å表ä¸çä»»æä¸ä¸ªå符串 |
| | | * |
| | | * @param str æå®å符串 |
| | | * @param testStrs éè¦æ£æ¥çå符串æ°ç» |
| | | * @return æ¯å¦å
å«ä»»æä¸ä¸ªå符串 |
| | | * @since 3.2.0 |
| | | */ |
| | | public static boolean containsAny(CharSequence str, CharSequence... testStrs) { |
| | | return null != getContainsStr(str, testStrs); |
| | | } |
| | | |
| | | /** |
| | | * æ¥æ¾æå®å符串æ¯å¦å
嫿å®å符串å表ä¸çä»»æä¸ä¸ªå符串ï¼å¦æå
å«è¿åæ¾å°ç第ä¸ä¸ªå符串 |
| | | * |
| | | * @param str æå®å符串 |
| | | * @param testStrs éè¦æ£æ¥çå符串æ°ç» |
| | | * @return 被å
å«ç第ä¸ä¸ªå符串 |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String getContainsStr(CharSequence str, CharSequence... testStrs) { |
| | | if (isEmpty(str) || Func.isEmpty(testStrs)) { |
| | | return null; |
| | | } |
| | | for (CharSequence checkStr : testStrs) { |
| | | if (str.toString().contains(checkStr)) { |
| | | return checkStr.toString(); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦å
å«ç¹å®å符ï¼å¿½ç¥å¤§å°åï¼å¦æç»å®ä¸¤ä¸ªåæ°é½ä¸º<code>null</code>ï¼è¿åtrue |
| | | * |
| | | * @param str è¢«æ£æµå符串 |
| | | * @param testStr 被æµè¯æ¯å¦å
å«çå符串 |
| | | * @return æ¯å¦å
å« |
| | | */ |
| | | public static boolean containsIgnoreCase(CharSequence str, CharSequence testStr) { |
| | | if (null == str) { |
| | | // å¦æè¢«çæµå符串å |
| | | return null == testStr; |
| | | } |
| | | return str.toString().toLowerCase().contains(testStr.toString().toLowerCase()); |
| | | } |
| | | |
| | | /** |
| | | * æ¥æ¾æå®å符串æ¯å¦å
嫿å®å符串å表ä¸çä»»æä¸ä¸ªå符串<br> |
| | | * 忽ç¥å¤§å°å |
| | | * |
| | | * @param str æå®å符串 |
| | | * @param testStrs éè¦æ£æ¥çå符串æ°ç» |
| | | * @return æ¯å¦å
å«ä»»æä¸ä¸ªå符串 |
| | | * @since 3.2.0 |
| | | */ |
| | | public static boolean containsAnyIgnoreCase(CharSequence str, CharSequence... testStrs) { |
| | | return null != getContainsStrIgnoreCase(str, testStrs); |
| | | } |
| | | |
| | | /** |
| | | * æ¥æ¾æå®å符串æ¯å¦å
嫿å®å符串å表ä¸çä»»æä¸ä¸ªå符串ï¼å¦æå
å«è¿åæ¾å°ç第ä¸ä¸ªå符串<br> |
| | | * 忽ç¥å¤§å°å |
| | | * |
| | | * @param str æå®å符串 |
| | | * @param testStrs éè¦æ£æ¥çå符串æ°ç» |
| | | * @return 被å
å«ç第ä¸ä¸ªå符串 |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String getContainsStrIgnoreCase(CharSequence str, CharSequence... testStrs) { |
| | | if (isEmpty(str) || Func.isEmpty(testStrs)) { |
| | | return null; |
| | | } |
| | | for (CharSequence testStr : testStrs) { |
| | | if (containsIgnoreCase(str, testStr)) { |
| | | return testStr.toString(); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * æ¹è¿JDK subString<br> |
| | | * indexä»0å¼å§è®¡ç®ï¼æåä¸ä¸ªå符为-1<br> |
| | | * 妿fromåtoä½ç½®ä¸æ ·ï¼è¿å "" <br> |
| | | * 妿fromætoä¸ºè´æ°ï¼åæç
§lengthä»åååæ°ä½ç½®ï¼å¦æç»å¯¹å¼å¤§äºå符串é¿åº¦ï¼åfromå½å°0ï¼toå½å°length<br> |
| | | * 妿ç»è¿ä¿®æ£çindexä¸from大äºtoï¼åäºæ¢fromåto example: <br> |
| | | * abcdefgh 2 3 =ã c <br> |
| | | * abcdefgh 2 -3 =ã cde <br> |
| | | * |
| | | * @param str String |
| | | * @param fromIndex å¼å§çindexï¼å
æ¬ï¼ |
| | | * @param toIndex ç»æçindexï¼ä¸å
æ¬ï¼ |
| | | * @return å串 |
| | | */ |
| | | public static String sub(CharSequence str, int fromIndex, int toIndex) { |
| | | if (isEmpty(str)) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | int len = str.length(); |
| | | |
| | | if (fromIndex < 0) { |
| | | fromIndex = len + fromIndex; |
| | | if (fromIndex < 0) { |
| | | fromIndex = 0; |
| | | } |
| | | } else if (fromIndex > len) { |
| | | fromIndex = len; |
| | | } |
| | | |
| | | if (toIndex < 0) { |
| | | toIndex = len + toIndex; |
| | | if (toIndex < 0) { |
| | | toIndex = len; |
| | | } |
| | | } else if (toIndex > len) { |
| | | toIndex = len; |
| | | } |
| | | |
| | | if (toIndex < fromIndex) { |
| | | int tmp = fromIndex; |
| | | fromIndex = toIndex; |
| | | toIndex = tmp; |
| | | } |
| | | |
| | | if (fromIndex == toIndex) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | |
| | | return str.toString().substring(fromIndex, toIndex); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * æªååéå符串ä¹åçå符串ï¼ä¸å
æ¬åéå符串<br> |
| | | * 妿ç»å®çå符串为空串ï¼nullæ""ï¼æè
åéå符串为nullï¼è¿ååå符串<br> |
| | | * 妿åéå符串为空串""ï¼åè¿å空串ï¼å¦æåéåç¬¦ä¸²æªæ¾å°ï¼è¿ååå符串 |
| | | * <p> |
| | | * æ åï¼ |
| | | * |
| | | * <pre> |
| | | * StringUtil.subBefore(null, *) = null |
| | | * StringUtil.subBefore("", *) = "" |
| | | * StringUtil.subBefore("abc", "a") = "" |
| | | * StringUtil.subBefore("abcba", "b") = "a" |
| | | * StringUtil.subBefore("abc", "c") = "ab" |
| | | * StringUtil.subBefore("abc", "d") = "abc" |
| | | * StringUtil.subBefore("abc", "") = "" |
| | | * StringUtil.subBefore("abc", null) = "abc" |
| | | * </pre> |
| | | * |
| | | * @param string è¢«æ¥æ¾çå符串 |
| | | * @param separator åéå符串ï¼ä¸å
æ¬ï¼ |
| | | * @param isLastSeparator æ¯å¦æ¥æ¾æåä¸ä¸ªåéå符串ï¼å¤æ¬¡åºç°åéå符串æ¶éåæåä¸ä¸ªï¼ï¼true为éåæåä¸ä¸ª |
| | | * @return åå²åçå符串 |
| | | * @since 3.1.1 |
| | | */ |
| | | public static String subBefore(CharSequence string, CharSequence separator, boolean isLastSeparator) { |
| | | if (isEmpty(string) || separator == null) { |
| | | return null == string ? null : string.toString(); |
| | | } |
| | | |
| | | final String str = string.toString(); |
| | | final String sep = separator.toString(); |
| | | if (sep.isEmpty()) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | final int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep); |
| | | if (pos == INDEX_NOT_FOUND) { |
| | | return str; |
| | | } |
| | | return str.substring(0, pos); |
| | | } |
| | | |
| | | /** |
| | | * æªååéå符串ä¹åçå符串ï¼ä¸å
æ¬åéå符串<br> |
| | | * 妿ç»å®çå符串为空串ï¼nullæ""ï¼ï¼è¿ååå符串<br> |
| | | * 妿åéå符串为空串ï¼nullæ""ï¼ï¼åè¿å空串ï¼å¦æåéåç¬¦ä¸²æªæ¾å°ï¼è¿å空串 |
| | | * <p> |
| | | * æ åï¼ |
| | | * |
| | | * <pre> |
| | | * StringUtil.subAfter(null, *) = null |
| | | * StringUtil.subAfter("", *) = "" |
| | | * StringUtil.subAfter(*, null) = "" |
| | | * StringUtil.subAfter("abc", "a") = "bc" |
| | | * StringUtil.subAfter("abcba", "b") = "cba" |
| | | * StringUtil.subAfter("abc", "c") = "" |
| | | * StringUtil.subAfter("abc", "d") = "" |
| | | * StringUtil.subAfter("abc", "") = "abc" |
| | | * </pre> |
| | | * |
| | | * @param string è¢«æ¥æ¾çå符串 |
| | | * @param separator åéå符串ï¼ä¸å
æ¬ï¼ |
| | | * @param isLastSeparator æ¯å¦æ¥æ¾æåä¸ä¸ªåéå符串ï¼å¤æ¬¡åºç°åéå符串æ¶éåæåä¸ä¸ªï¼ï¼true为éåæåä¸ä¸ª |
| | | * @return åå²åçå符串 |
| | | * @since 3.1.1 |
| | | */ |
| | | public static String subAfter(CharSequence string, CharSequence separator, boolean isLastSeparator) { |
| | | if (isEmpty(string)) { |
| | | return null == string ? null : string.toString(); |
| | | } |
| | | if (separator == null) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | final String str = string.toString(); |
| | | final String sep = separator.toString(); |
| | | final int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep); |
| | | if (pos == INDEX_NOT_FOUND) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | return str.substring(pos + separator.length()); |
| | | } |
| | | |
| | | /** |
| | | * æªåæå®å符串ä¸é´é¨åï¼ä¸å
æ¬æ è¯å符串<br> |
| | | * <p> |
| | | * æ åï¼ |
| | | * |
| | | * <pre> |
| | | * StringUtil.subBetween("wx[b]yz", "[", "]") = "b" |
| | | * StringUtil.subBetween(null, *, *) = null |
| | | * StringUtil.subBetween(*, null, *) = null |
| | | * StringUtil.subBetween(*, *, null) = null |
| | | * StringUtil.subBetween("", "", "") = "" |
| | | * StringUtil.subBetween("", "", "]") = null |
| | | * StringUtil.subBetween("", "[", "]") = null |
| | | * StringUtil.subBetween("yabcz", "", "") = "" |
| | | * StringUtil.subBetween("yabcz", "y", "z") = "abc" |
| | | * StringUtil.subBetween("yabczyabcz", "y", "z") = "abc" |
| | | * </pre> |
| | | * |
| | | * @param str 被åå²çå符串 |
| | | * @param before æªåå¼å§çå符串æ è¯ |
| | | * @param after æªåå°çå符串æ è¯ |
| | | * @return æªååçå符串 |
| | | * @since 3.1.1 |
| | | */ |
| | | public static String subBetween(CharSequence str, CharSequence before, CharSequence after) { |
| | | if (str == null || before == null || after == null) { |
| | | return null; |
| | | } |
| | | |
| | | final String str2 = str.toString(); |
| | | final String before2 = before.toString(); |
| | | final String after2 = after.toString(); |
| | | |
| | | final int start = str2.indexOf(before2); |
| | | if (start != INDEX_NOT_FOUND) { |
| | | final int end = str2.indexOf(after2, start + before2.length()); |
| | | if (end != INDEX_NOT_FOUND) { |
| | | return str2.substring(start + before2.length(), end); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * æªåæå®å符串ä¸é´é¨åï¼ä¸å
æ¬æ è¯å符串<br> |
| | | * <p> |
| | | * æ åï¼ |
| | | * |
| | | * <pre> |
| | | * StringUtil.subBetween(null, *) = null |
| | | * StringUtil.subBetween("", "") = "" |
| | | * StringUtil.subBetween("", "tag") = null |
| | | * StringUtil.subBetween("tagabctag", null) = null |
| | | * StringUtil.subBetween("tagabctag", "") = "" |
| | | * StringUtil.subBetween("tagabctag", "tag") = "abc" |
| | | * </pre> |
| | | * |
| | | * @param str 被åå²çå符串 |
| | | * @param beforeAndAfter æªåå¼å§åç»æçå符串æ è¯ |
| | | * @return æªååçå符串 |
| | | * @since 3.1.1 |
| | | */ |
| | | public static String subBetween(CharSequence str, CharSequence beforeAndAfter) { |
| | | return subBetween(str, beforeAndAfter, beforeAndAfter); |
| | | } |
| | | |
| | | /** |
| | | * 廿æå®åç¼ |
| | | * |
| | | * @param str å符串 |
| | | * @param prefix åç¼ |
| | | * @return åæåçå符串ï¼è¥åç¼ä¸æ¯ preffixï¼ è¿ååå符串 |
| | | */ |
| | | public static String removePrefix(CharSequence str, CharSequence prefix) { |
| | | if (isEmpty(str) || isEmpty(prefix)) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | |
| | | final String str2 = str.toString(); |
| | | if (str2.startsWith(prefix.toString())) { |
| | | return subSuf(str2, prefix.length()); |
| | | } |
| | | return str2; |
| | | } |
| | | |
| | | /** |
| | | * 忽ç¥å¤§å°å廿æå®åç¼ |
| | | * |
| | | * @param str å符串 |
| | | * @param prefix åç¼ |
| | | * @return åæåçå符串ï¼è¥åç¼ä¸æ¯ prefixï¼ è¿ååå符串 |
| | | */ |
| | | public static String removePrefixIgnoreCase(CharSequence str, CharSequence prefix) { |
| | | if (isEmpty(str) || isEmpty(prefix)) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | |
| | | final String str2 = str.toString(); |
| | | if (str2.toLowerCase().startsWith(prefix.toString().toLowerCase())) { |
| | | return subSuf(str2, prefix.length()); |
| | | } |
| | | return str2; |
| | | } |
| | | |
| | | /** |
| | | * 廿æå®åç¼ |
| | | * |
| | | * @param str å符串 |
| | | * @param suffix åç¼ |
| | | * @return åæåçå符串ï¼è¥åç¼ä¸æ¯ suffixï¼ è¿ååå符串 |
| | | */ |
| | | public static String removeSuffix(CharSequence str, CharSequence suffix) { |
| | | if (isEmpty(str) || isEmpty(suffix)) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | |
| | | final String str2 = str.toString(); |
| | | if (str2.endsWith(suffix.toString())) { |
| | | return subPre(str2, str2.length() - suffix.length()); |
| | | } |
| | | return str2; |
| | | } |
| | | |
| | | /** |
| | | * 廿æå®åç¼ï¼å¹¶å°åé¦åæ¯ |
| | | * |
| | | * @param str å符串 |
| | | * @param suffix åç¼ |
| | | * @return åæåçå符串ï¼è¥åç¼ä¸æ¯ suffixï¼ è¿ååå符串 |
| | | */ |
| | | public static String removeSufAndLowerFirst(CharSequence str, CharSequence suffix) { |
| | | return firstCharToLower(removeSuffix(str, suffix)); |
| | | } |
| | | |
| | | /** |
| | | * 忽ç¥å¤§å°å廿æå®åç¼ |
| | | * |
| | | * @param str å符串 |
| | | * @param suffix åç¼ |
| | | * @return åæåçå符串ï¼è¥åç¼ä¸æ¯ suffixï¼ è¿ååå符串 |
| | | */ |
| | | public static String removeSuffixIgnoreCase(CharSequence str, CharSequence suffix) { |
| | | if (isEmpty(str) || isEmpty(suffix)) { |
| | | return StringPool.EMPTY; |
| | | } |
| | | |
| | | final String str2 = str.toString(); |
| | | if (str2.toLowerCase().endsWith(suffix.toString().toLowerCase())) { |
| | | return subPre(str2, str2.length() - suffix.length()); |
| | | } |
| | | return str2; |
| | | } |
| | | |
| | | /** |
| | | * é¦åæ¯åå°å |
| | | * |
| | | * @param str å符串 |
| | | * @return {String} |
| | | */ |
| | | public static String firstCharToLower(String str) { |
| | | char firstChar = str.charAt(0); |
| | | if (firstChar >= CharPool.UPPER_A && firstChar <= CharPool.UPPER_Z) { |
| | | char[] arr = str.toCharArray(); |
| | | arr[0] += (CharPool.LOWER_A - CharPool.UPPER_A); |
| | | return new String(arr); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * é¦åæ¯å大å |
| | | * |
| | | * @param str å符串 |
| | | * @return {String} |
| | | */ |
| | | public static String firstCharToUpper(String str) { |
| | | char firstChar = str.charAt(0); |
| | | if (firstChar >= CharPool.LOWER_A && firstChar <= CharPool.LOWER_Z) { |
| | | char[] arr = str.toCharArray(); |
| | | arr[0] -= (CharPool.LOWER_A - CharPool.UPPER_A); |
| | | return new String(arr); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * å岿å®ä½ç½®ä¹åé¨åçå符串 |
| | | * |
| | | * @param string å符串 |
| | | * @param toIndex åå²å°çä½ç½®ï¼ä¸å
æ¬ï¼ |
| | | * @return åå²åçå©ä½çååé¨åå符串 |
| | | */ |
| | | public static String subPre(CharSequence string, int toIndex) { |
| | | return sub(string, 0, toIndex); |
| | | } |
| | | |
| | | /** |
| | | * å岿å®ä½ç½®ä¹åé¨åçå符串 |
| | | * |
| | | * @param string å符串 |
| | | * @param fromIndex åå²å¼å§çä½ç½®ï¼å
æ¬ï¼ |
| | | * @return åå²ååå©ä½çååé¨åå符串 |
| | | */ |
| | | public static String subSuf(CharSequence string, int fromIndex) { |
| | | if (isEmpty(string)) { |
| | | return null; |
| | | } |
| | | return sub(string, fromIndex, string.length()); |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾æå®å符 |
| | | * |
| | | * @param str å符串 |
| | | * @param searchChar è¢«æ¥æ¾çå符 |
| | | * @return ä½ç½® |
| | | */ |
| | | public static int indexOf(final CharSequence str, char searchChar) { |
| | | return indexOf(str, searchChar, 0); |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾æå®å符 |
| | | * |
| | | * @param str å符串 |
| | | * @param searchChar è¢«æ¥æ¾çå符 |
| | | * @param start èµ·å§ä½ç½®ï¼å¦æå°äº0ï¼ä»0å¼å§æ¥æ¾ |
| | | * @return ä½ç½® |
| | | */ |
| | | public static int indexOf(final CharSequence str, char searchChar, int start) { |
| | | if (str instanceof String) { |
| | | return ((String) str).indexOf(searchChar, start); |
| | | } else { |
| | | return indexOf(str, searchChar, start, -1); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾æå®å符 |
| | | * |
| | | * @param str å符串 |
| | | * @param searchChar è¢«æ¥æ¾çå符 |
| | | * @param start èµ·å§ä½ç½®ï¼å¦æå°äº0ï¼ä»0å¼å§æ¥æ¾ |
| | | * @param end ç»æ¢ä½ç½®ï¼å¦æè¶
è¿str.length()åé»è®¤æ¥æ¾å°å符串æ«å°¾ |
| | | * @return ä½ç½® |
| | | */ |
| | | public static int indexOf(final CharSequence str, char searchChar, int start, int end) { |
| | | final int len = str.length(); |
| | | if (start < 0 || start > len) { |
| | | start = 0; |
| | | } |
| | | if (end > len || end < 0) { |
| | | end = len; |
| | | } |
| | | for (int i = start; i < end; i++) { |
| | | if (str.charAt(i) == searchChar) { |
| | | return i; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾å符串ï¼å¿½ç¥å¤§å°å<br> |
| | | * |
| | | * <pre> |
| | | * StringUtil.indexOfIgnoreCase(null, *, *) = -1 |
| | | * StringUtil.indexOfIgnoreCase(*, null, *) = -1 |
| | | * StringUtil.indexOfIgnoreCase("", "", 0) = 0 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "", 2) = 2 |
| | | * StringUtil.indexOfIgnoreCase("abc", "", 9) = -1 |
| | | * </pre> |
| | | * |
| | | * @param str å符串 |
| | | * @param searchStr éè¦æ¥æ¾ä½ç½®çå符串 |
| | | * @return ä½ç½® |
| | | * @since 3.2.1 |
| | | */ |
| | | public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { |
| | | return indexOfIgnoreCase(str, searchStr, 0); |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾å符串 |
| | | * |
| | | * <pre> |
| | | * StringUtil.indexOfIgnoreCase(null, *, *) = -1 |
| | | * StringUtil.indexOfIgnoreCase(*, null, *) = -1 |
| | | * StringUtil.indexOfIgnoreCase("", "", 0) = 0 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 |
| | | * StringUtil.indexOfIgnoreCase("aabaabaa", "", 2) = 2 |
| | | * StringUtil.indexOfIgnoreCase("abc", "", 9) = -1 |
| | | * </pre> |
| | | * |
| | | * @param str å符串 |
| | | * @param searchStr éè¦æ¥æ¾ä½ç½®çå符串 |
| | | * @param fromIndex èµ·å§ä½ç½® |
| | | * @return ä½ç½® |
| | | * @since 3.2.1 |
| | | */ |
| | | public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int fromIndex) { |
| | | return indexOf(str, searchStr, fromIndex, true); |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
å忥æ¾å符串 |
| | | * |
| | | * @param str å符串 |
| | | * @param searchStr éè¦æ¥æ¾ä½ç½®çå符串 |
| | | * @param fromIndex èµ·å§ä½ç½® |
| | | * @param ignoreCase æ¯å¦å¿½ç¥å¤§å°å |
| | | * @return ä½ç½® |
| | | * @since 3.2.1 |
| | | */ |
| | | public static int indexOf(final CharSequence str, CharSequence searchStr, int fromIndex, boolean ignoreCase) { |
| | | if (str == null || searchStr == null) { |
| | | return INDEX_NOT_FOUND; |
| | | } |
| | | if (fromIndex < 0) { |
| | | fromIndex = 0; |
| | | } |
| | | |
| | | final int endLimit = str.length() - searchStr.length() + 1; |
| | | if (fromIndex > endLimit) { |
| | | return INDEX_NOT_FOUND; |
| | | } |
| | | if (searchStr.length() == 0) { |
| | | return fromIndex; |
| | | } |
| | | |
| | | if (false == ignoreCase) { |
| | | // ä¸å¿½ç¥å¤§å°åè°ç¨JDKæ¹æ³ |
| | | return str.toString().indexOf(searchStr.toString(), fromIndex); |
| | | } |
| | | |
| | | for (int i = fromIndex; i < endLimit; i++) { |
| | | if (isSubEquals(str, i, searchStr, 0, searchStr.length(), true)) { |
| | | return i; |
| | | } |
| | | } |
| | | return INDEX_NOT_FOUND; |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾å符串ï¼å¿½ç¥å¤§å°å<br> |
| | | * |
| | | * @param str å符串 |
| | | * @param searchStr éè¦æ¥æ¾ä½ç½®çå符串 |
| | | * @return ä½ç½® |
| | | * @since 3.2.1 |
| | | */ |
| | | public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { |
| | | return lastIndexOfIgnoreCase(str, searchStr, str.length()); |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾å符串ï¼å¿½ç¥å¤§å°å<br> |
| | | * |
| | | * @param str å符串 |
| | | * @param searchStr éè¦æ¥æ¾ä½ç½®çå符串 |
| | | * @param fromIndex èµ·å§ä½ç½®ï¼ä»åå¾åè®¡æ° |
| | | * @return ä½ç½® |
| | | * @since 3.2.1 |
| | | */ |
| | | public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int fromIndex) { |
| | | return lastIndexOf(str, searchStr, fromIndex, true); |
| | | } |
| | | |
| | | /** |
| | | * æå®èå´å
æ¥æ¾å符串<br> |
| | | * |
| | | * @param str å符串 |
| | | * @param searchStr éè¦æ¥æ¾ä½ç½®çå符串 |
| | | * @param fromIndex èµ·å§ä½ç½®ï¼ä»åå¾åè®¡æ° |
| | | * @param ignoreCase æ¯å¦å¿½ç¥å¤§å°å |
| | | * @return ä½ç½® |
| | | * @since 3.2.1 |
| | | */ |
| | | public static int lastIndexOf(final CharSequence str, final CharSequence searchStr, int fromIndex, boolean ignoreCase) { |
| | | if (str == null || searchStr == null) { |
| | | return INDEX_NOT_FOUND; |
| | | } |
| | | if (fromIndex < 0) { |
| | | fromIndex = 0; |
| | | } |
| | | fromIndex = Math.min(fromIndex, str.length()); |
| | | |
| | | if (searchStr.length() == 0) { |
| | | return fromIndex; |
| | | } |
| | | |
| | | if (false == ignoreCase) { |
| | | // ä¸å¿½ç¥å¤§å°åè°ç¨JDKæ¹æ³ |
| | | return str.toString().lastIndexOf(searchStr.toString(), fromIndex); |
| | | } |
| | | |
| | | for (int i = fromIndex; i > 0; i--) { |
| | | if (isSubEquals(str, i, searchStr, 0, searchStr.length(), true)) { |
| | | return i; |
| | | } |
| | | } |
| | | return INDEX_NOT_FOUND; |
| | | } |
| | | |
| | | /** |
| | | * è¿åå符串 searchStr å¨å符串 str ä¸ç¬¬ ordinal 次åºç°çä½ç½®ã<br> |
| | | * æ¤æ¹æ³æ¥èªï¼Apache-Commons-Lang |
| | | * <p> |
| | | * æ åï¼*代表任æå符ï¼ï¼ |
| | | * |
| | | * <pre> |
| | | * StringUtil.ordinalIndexOf(null, *, *) = -1 |
| | | * StringUtil.ordinalIndexOf(*, null, *) = -1 |
| | | * StringUtil.ordinalIndexOf("", "", *) = 0 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "a", 1) = 0 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "a", 2) = 1 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "b", 1) = 2 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "b", 2) = 5 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "ab", 1) = 1 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "ab", 2) = 4 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "", 1) = 0 |
| | | * StringUtil.ordinalIndexOf("aabaabaa", "", 2) = 0 |
| | | * </pre> |
| | | * |
| | | * @param str è¢«æ£æ¥çå符串ï¼å¯ä»¥ä¸ºnull |
| | | * @param searchStr è¢«æ¥æ¾çå符串ï¼å¯ä»¥ä¸ºnull |
| | | * @param ordinal ç¬¬å æ¬¡åºç°çä½ç½® |
| | | * @return æ¥æ¾å°çä½ç½® |
| | | * @since 3.2.3 |
| | | */ |
| | | public static int ordinalIndexOf(String str, String searchStr, int ordinal) { |
| | | if (str == null || searchStr == null || ordinal <= 0) { |
| | | return INDEX_NOT_FOUND; |
| | | } |
| | | if (searchStr.length() == 0) { |
| | | return 0; |
| | | } |
| | | int found = 0; |
| | | int index = INDEX_NOT_FOUND; |
| | | do { |
| | | index = str.indexOf(searchStr, index + 1); |
| | | if (index < 0) { |
| | | return index; |
| | | } |
| | | found++; |
| | | } while (found < ordinal); |
| | | return index; |
| | | } |
| | | |
| | | /** |
| | | * æªå两个å符串çä¸åé¨åï¼é¿åº¦ä¸è´ï¼ï¼å¤ææªåçå串æ¯å¦ç¸å<br> |
| | | * ä»»æä¸ä¸ªå符串为nullè¿åfalse |
| | | * |
| | | * @param str1 第ä¸ä¸ªå符串 |
| | | * @param start1 第ä¸ä¸ªå符串å¼å§çä½ç½® |
| | | * @param str2 第äºä¸ªå符串 |
| | | * @param start2 第äºä¸ªå符串å¼å§çä½ç½® |
| | | * @param length æªåé¿åº¦ |
| | | * @param ignoreCase æ¯å¦å¿½ç¥å¤§å°å |
| | | * @return å串æ¯å¦ç¸å |
| | | * @since 3.2.1 |
| | | */ |
| | | public static boolean isSubEquals(CharSequence str1, int start1, CharSequence str2, int start2, int length, boolean ignoreCase) { |
| | | if (null == str1 || null == str2) { |
| | | return false; |
| | | } |
| | | |
| | | return str1.toString().regionMatches(ignoreCase, start1, str2.toString(), start2, length); |
| | | } |
| | | |
| | | /** |
| | | * æ¯è¾ä¸¤ä¸ªå符串ï¼å¤§å°åææï¼ã |
| | | * |
| | | * <pre> |
| | | * equalsIgnoreCase(null, null) = true |
| | | * equalsIgnoreCase(null, "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 {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(); |
| | | } |
| | | |
| | | |
| | | } |
| | | |