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                sb.append('_');
096            }
097            sb.append(Character.toLowerCase(c));
098        }
099        return sb.toString();
100    }
101
102    /**
103     * 下划线转驼峰格式
104     *
105     * @param string
106     */
107    public static String underlineToCamel(String string) {
108        if (isBlank(string)) {
109            return "";
110        }
111        if (Character.isUpperCase(string.charAt(0))) {
112            string = string.toLowerCase();
113        }
114        int strLen = string.length();
115        StringBuilder sb = new StringBuilder(strLen);
116        for (int i = 0; i < strLen; i++) {
117            char c = string.charAt(i);
118            if (c == '_') {
119                if (++i < strLen) {
120                    sb.append(Character.toUpperCase(string.charAt(i)));
121                }
122            } else {
123                sb.append(c);
124            }
125        }
126        return sb.toString();
127    }
128
129
130    /**
131     * 删除字符串中的字符
132     */
133    public static String deleteChar(String string, char deleteChar) {
134        if (isBlank(string)) {
135            return "";
136        }
137        char[] chars = string.toCharArray();
138        StringBuilder sb = new StringBuilder(string.length());
139        for (char aChar : chars) {
140            if (aChar != deleteChar) {
141                sb.append(aChar);
142            }
143        }
144        return sb.toString();
145    }
146
147    public static String deleteChar(String string, char deleteChar1, char deleteChar2) {
148        if (isBlank(string)) {
149            return "";
150        }
151        char[] chars = string.toCharArray();
152        StringBuilder sb = new StringBuilder(string.length());
153        for (char aChar : chars) {
154            if (aChar != deleteChar1 && aChar != deleteChar2) {
155                sb.append(aChar);
156            }
157        }
158        return sb.toString();
159    }
160
161    /**
162     * 字符串为 null 或者内部字符全部为 ' ', '\t', '\n', '\r' 这四类字符时返回 true
163     */
164    public static boolean isBlank(String string) {
165        if (string == null) {
166            return true;
167        }
168
169        for (int i = 0, len = string.length(); i < len; i++) {
170            if (string.charAt(i) > ' ') {
171                return false;
172            }
173        }
174        return true;
175    }
176
177
178    public static boolean isAnyBlank(String... strings) {
179        if (strings == null || strings.length == 0) {
180            throw new IllegalArgumentException("strings is null or empty.");
181        }
182
183        for (String string : strings) {
184            if (isBlank(string)) {
185                return true;
186            }
187        }
188        return false;
189    }
190
191
192    public static boolean isNotBlank(String str) {
193        return !isBlank(str);
194    }
195
196
197    public static boolean areNotBlank(String... strings) {
198        return !isAnyBlank(strings);
199    }
200
201
202    /**
203     * 这个字符串是否是全是数字
204     *
205     * @param string
206     * @return 全部数数值时返回 true,否则返回 false
207     */
208    public static boolean isNumeric(String string) {
209        if (isBlank(string)) {
210            return false;
211        }
212        for (int i = string.length(); --i >= 0; ) {
213            int chr = string.charAt(i);
214            if (chr < 48 || chr > 57) {
215                return false;
216            }
217        }
218        return true;
219    }
220
221
222    public static boolean startsWithAny(String string, String... prefixes) {
223        if (isBlank(string) || prefixes == null) {
224            return false;
225        }
226
227        for (String prefix : prefixes) {
228            if (string.startsWith(prefix)) {
229                return true;
230            }
231        }
232        return false;
233    }
234
235
236    public static boolean endsWithAny(String str, String... suffixes) {
237        if (isBlank(str) || suffixes == null) {
238            return false;
239        }
240
241        for (String suffix : suffixes) {
242            if (str.endsWith(suffix)) {
243                return true;
244            }
245        }
246        return false;
247    }
248
249
250    /**
251     * 正则匹配
252     *
253     * @param regex
254     * @param input
255     * @return
256     */
257    public static boolean matches(String regex, String input) {
258        if (null == regex || null == input) {
259            return false;
260        }
261        return Pattern.matches(regex, input);
262    }
263
264    /**
265     * 合并字符串,优化 String.join() 方法
266     *
267     * @param delimiter
268     * @param elements
269     * @return 新拼接好的字符串
270     * @see String#join(CharSequence, CharSequence...)
271     */
272    public static String join(String delimiter, CharSequence... elements) {
273        if (ArrayUtil.isEmpty(elements)) {
274            return "";
275        } else if (elements.length == 1) {
276            return String.valueOf(elements[0]);
277        } else {
278            return String.join(delimiter, elements);
279        }
280    }
281
282    /**
283     * 合并字符串,优化 String.join() 方法
284     *
285     * @param delimiter
286     * @param elements
287     * @return 新拼接好的字符串
288     * @see String#join(CharSequence, CharSequence...)
289     */
290    public static String join(String delimiter, Collection<? extends CharSequence> elements) {
291        if (CollectionUtil.isEmpty(elements)) {
292            return "";
293        } else if (elements.size() == 1) {
294            return String.valueOf(elements.iterator().next());
295        } else {
296            return String.join(delimiter, elements);
297        }
298    }
299
300
301    /**
302     * 合并字符串,优化 String.join() 方法
303     *
304     * @param delimiter
305     * @param objs
306     * @param function
307     * @param <T>
308     */
309    public static <T> String join(String delimiter, Collection<T> objs, Function<T, String> function) {
310        if (CollectionUtil.isEmpty(objs)) {
311            return "";
312        } else if (objs.size() == 1) {
313            T next = objs.iterator().next();
314            return String.valueOf(function.apply(next));
315        } else {
316            String[] strings = new String[objs.size()];
317            int index = 0;
318            for (T obj : objs) {
319                strings[index++] = function.apply(obj);
320            }
321            return String.join(delimiter, strings);
322        }
323    }
324
325    public static String buildSchemaWithTable(String schema, String tableName) {
326        return isNotBlank(schema) ? schema + "." + tableName : tableName;
327    }
328
329    public static String[] getSchemaAndTableName(String tableNameWithSchema) {
330        int index = tableNameWithSchema.indexOf(".");
331        return index <= 0 ? new String[]{null, tableNameWithSchema.trim()}
332            : new String[]{tableNameWithSchema.substring(0, index).trim(), tableNameWithSchema.substring(index + 1).trim()};
333    }
334
335    public static String[] getTableNameWithAlias(String tableNameWithAlias) {
336        int index = tableNameWithAlias.indexOf(".");
337        return index <= 0 ? new String[]{tableNameWithAlias, null}
338            : new String[]{tableNameWithAlias.substring(0, index), tableNameWithAlias.substring(index + 1)};
339    }
340
341    public static String tryTrim(String string) {
342        return string != null ? string.trim() : null;
343    }
344
345    public static String substringAfterLast(String text, String prefix) {
346        if (text == null) {
347            return null;
348        }
349        if (prefix == null) {
350            return text;
351        }
352        return text.substring(text.lastIndexOf(prefix) + 1);
353    }
354
355
356}