001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.util; 017 018 019import com.mybatisflex.core.exception.FlexExceptions; 020 021import java.util.Collection; 022import java.util.Locale; 023import java.util.function.Function; 024import java.util.regex.Pattern; 025 026public class StringUtil { 027 028 private StringUtil() { 029 } 030 031 /** 032 * @see org.apache.ibatis.reflection.property.PropertyNamer#methodToProperty(String) 033 */ 034 public static String methodToProperty(String name) { 035 if (name.startsWith("is")) { 036 name = name.substring(2); 037 } else if (name.startsWith("get") || name.startsWith("set")) { 038 name = name.substring(3); 039 } else { 040 throw FlexExceptions.wrap("Error parsing property name '%s'. Didn't start with 'is', 'get' or 'set'.", name); 041 } 042 if (!name.isEmpty()) { 043 name = name.substring(0, 1).toLowerCase(Locale.ENGLISH).concat(name.substring(1)); 044 } 045 return name; 046 } 047 048 049 /** 050 * 第一个字符转换为小写 051 * 052 * @param string 053 */ 054 public static String firstCharToLowerCase(String string) { 055 char firstChar = string.charAt(0); 056 if (firstChar >= 'A' && firstChar <= 'Z') { 057 char[] chars = string.toCharArray(); 058 chars[0] += ('a' - 'A'); 059 return new String(chars); 060 } 061 return string; 062 } 063 064 065 /** 066 * 第一个字符转换为大写 067 * 068 * @param string 069 */ 070 public static String firstCharToUpperCase(String string) { 071 char firstChar = string.charAt(0); 072 if (firstChar >= 'a' && firstChar <= 'z') { 073 char[] chars = string.toCharArray(); 074 chars[0] -= ('a' - 'A'); 075 return new String(chars); 076 } 077 return string; 078 } 079 080 081 /** 082 * 驼峰转下划线格式 083 * 084 * @param string 085 */ 086 public static String camelToUnderline(String string) { 087 if (isBlank(string)) { 088 return ""; 089 } 090 int strLen = string.length(); 091 StringBuilder sb = new StringBuilder(strLen); 092 for (int i = 0; i < strLen; i++) { 093 char c = string.charAt(i); 094 if (Character.isUpperCase(c) && i > 0) { 095 char prev = string.charAt(i - 1); 096 if (!Character.isUpperCase(prev) && prev != '_') { 097 sb.append('_'); 098 } 099 } 100 sb.append(Character.toLowerCase(c)); 101 } 102 return sb.toString(); 103 } 104 105 /** 106 * 下划线转驼峰格式 107 * 108 * @param string 109 */ 110 public static String underlineToCamel(String string) { 111 if (isBlank(string)) { 112 return ""; 113 } 114 if (Character.isUpperCase(string.charAt(0))) { 115 string = string.toLowerCase(); 116 } 117 int strLen = string.length(); 118 StringBuilder sb = new StringBuilder(strLen); 119 for (int i = 0; i < strLen; i++) { 120 char c = string.charAt(i); 121 if (c == '_') { 122 if (++i < strLen) { 123 sb.append(Character.toUpperCase(string.charAt(i))); 124 } 125 } else { 126 sb.append(c); 127 } 128 } 129 return sb.toString(); 130 } 131 132 133 /** 134 * 删除字符串中的字符 135 */ 136 public static String deleteChar(String string, char deleteChar) { 137 if (isBlank(string)) { 138 return ""; 139 } 140 char[] chars = string.toCharArray(); 141 StringBuilder sb = new StringBuilder(string.length()); 142 for (char aChar : chars) { 143 if (aChar != deleteChar) { 144 sb.append(aChar); 145 } 146 } 147 return sb.toString(); 148 } 149 150 public static String deleteChar(String string, char deleteChar1, char deleteChar2) { 151 if (isBlank(string)) { 152 return ""; 153 } 154 char[] chars = string.toCharArray(); 155 StringBuilder sb = new StringBuilder(string.length()); 156 for (char aChar : chars) { 157 if (aChar != deleteChar1 && aChar != deleteChar2) { 158 sb.append(aChar); 159 } 160 } 161 return sb.toString(); 162 } 163 164 /** 165 * 字符串为 null 或者内部字符全部为 ' ', '\t', '\n', '\r' 这四类字符时返回 true 166 */ 167 public static boolean isBlank(String string) { 168 if (string == null) { 169 return true; 170 } 171 172 for (int i = 0, len = string.length(); i < len; i++) { 173 if (string.charAt(i) > ' ') { 174 return false; 175 } 176 } 177 return true; 178 } 179 180 181 public static boolean isAnyBlank(String... strings) { 182 if (strings == null || strings.length == 0) { 183 throw new IllegalArgumentException("strings is null or empty."); 184 } 185 186 for (String string : strings) { 187 if (isBlank(string)) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 195 public static boolean isNotBlank(String str) { 196 return !isBlank(str); 197 } 198 199 200 public static boolean areNotBlank(String... strings) { 201 return !isAnyBlank(strings); 202 } 203 204 205 /** 206 * 这个字符串是否是全是数字 207 * 208 * @param string 209 * @return 全部数数值时返回 true,否则返回 false 210 */ 211 public static boolean isNumeric(String string) { 212 if (isBlank(string)) { 213 return false; 214 } 215 for (int i = string.length(); --i >= 0; ) { 216 int chr = string.charAt(i); 217 if (chr < 48 || chr > 57) { 218 return false; 219 } 220 } 221 return true; 222 } 223 224 225 public static boolean startsWithAny(String string, String... prefixes) { 226 if (isBlank(string) || prefixes == null) { 227 return false; 228 } 229 230 for (String prefix : prefixes) { 231 if (string.startsWith(prefix)) { 232 return true; 233 } 234 } 235 return false; 236 } 237 238 239 public static boolean endsWithAny(String str, String... suffixes) { 240 if (isBlank(str) || suffixes == null) { 241 return false; 242 } 243 244 for (String suffix : suffixes) { 245 if (str.endsWith(suffix)) { 246 return true; 247 } 248 } 249 return false; 250 } 251 252 253 /** 254 * 正则匹配 255 * 256 * @param regex 257 * @param input 258 * @return 259 */ 260 public static boolean matches(String regex, String input) { 261 if (null == regex || null == input) { 262 return false; 263 } 264 return Pattern.matches(regex, input); 265 } 266 267 /** 268 * 合并字符串,优化 String.join() 方法 269 * 270 * @param delimiter 271 * @param elements 272 * @return 新拼接好的字符串 273 * @see String#join(CharSequence, CharSequence...) 274 */ 275 public static String join(String delimiter, CharSequence... elements) { 276 if (ArrayUtil.isEmpty(elements)) { 277 return ""; 278 } else if (elements.length == 1) { 279 return String.valueOf(elements[0]); 280 } else { 281 return String.join(delimiter, elements); 282 } 283 } 284 285 /** 286 * 合并字符串,优化 String.join() 方法 287 * 288 * @param delimiter 289 * @param elements 290 * @return 新拼接好的字符串 291 * @see String#join(CharSequence, CharSequence...) 292 */ 293 public static String join(String delimiter, Collection<? extends CharSequence> elements) { 294 if (CollectionUtil.isEmpty(elements)) { 295 return ""; 296 } else if (elements.size() == 1) { 297 return String.valueOf(elements.iterator().next()); 298 } else { 299 return String.join(delimiter, elements); 300 } 301 } 302 303 304 /** 305 * 合并字符串,优化 String.join() 方法 306 * 307 * @param delimiter 308 * @param objs 309 * @param function 310 * @param <T> 311 */ 312 public static <T> String join(String delimiter, Collection<T> objs, Function<T, String> function) { 313 if (CollectionUtil.isEmpty(objs)) { 314 return ""; 315 } else if (objs.size() == 1) { 316 T next = objs.iterator().next(); 317 return String.valueOf(function.apply(next)); 318 } else { 319 String[] strings = new String[objs.size()]; 320 int index = 0; 321 for (T obj : objs) { 322 strings[index++] = function.apply(obj); 323 } 324 return String.join(delimiter, strings); 325 } 326 } 327 328 public static String buildSchemaWithTable(String schema, String tableName) { 329 return isNotBlank(schema) ? schema + "." + tableName : tableName; 330 } 331 332 public static String[] getSchemaAndTableName(String tableNameWithSchema) { 333 int index = tableNameWithSchema.indexOf("."); 334 return index <= 0 ? new String[]{null, tableNameWithSchema.trim()} 335 : new String[]{tableNameWithSchema.substring(0, index).trim(), tableNameWithSchema.substring(index + 1).trim()}; 336 } 337 338 public static String[] getTableNameWithAlias(String tableNameWithAlias) { 339 int index = tableNameWithAlias.indexOf("."); 340 return index <= 0 ? new String[]{tableNameWithAlias, null} 341 : new String[]{tableNameWithAlias.substring(0, index), tableNameWithAlias.substring(index + 1)}; 342 } 343 344 public static String tryTrim(String string) { 345 return string != null ? string.trim() : null; 346 } 347 348 public static String substringAfterLast(String text, String prefix) { 349 if (text == null) { 350 return null; 351 } 352 if (prefix == null) { 353 return text; 354 } 355 return text.substring(text.lastIndexOf(prefix) + 1); 356 } 357 358 359}