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}