2022-07-20 13:18:57 +02:00
|
|
|
package fr.pandacube.lib.util;
|
2016-02-16 20:07:51 +01:00
|
|
|
|
2021-08-15 03:24:56 +02:00
|
|
|
import java.util.Arrays;
|
2018-07-21 17:57:44 +02:00
|
|
|
import java.util.List;
|
2022-08-13 00:55:44 +02:00
|
|
|
import java.util.function.Predicate;
|
2022-08-14 00:29:23 +02:00
|
|
|
import java.util.function.UnaryOperator;
|
2022-08-13 00:55:44 +02:00
|
|
|
import java.util.regex.Matcher;
|
|
|
|
import java.util.regex.Pattern;
|
2018-07-21 17:57:44 +02:00
|
|
|
|
2022-07-28 01:13:35 +02:00
|
|
|
/**
|
|
|
|
* Provides various methods to manipulate Strings.
|
|
|
|
*/
|
2016-02-16 20:07:51 +01:00
|
|
|
public class StringUtil {
|
2022-07-28 01:13:35 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Format the provided double, omitting the decimal part if the provided double is strictly equals to a long value.
|
|
|
|
* @param d the value to convert to string.
|
|
|
|
* @return a string representation of the double value.
|
|
|
|
*/
|
2016-07-14 14:22:23 +02:00
|
|
|
public static String formatDouble(double d) {
|
2016-10-17 00:03:04 +02:00
|
|
|
if (d == (long) d)
|
|
|
|
return String.format("%d", (long) d);
|
|
|
|
return String.valueOf(d);
|
2016-02-16 20:07:51 +01:00
|
|
|
}
|
2016-07-14 14:22:23 +02:00
|
|
|
|
2016-02-16 20:07:51 +01:00
|
|
|
/**
|
2022-07-28 01:13:35 +02:00
|
|
|
* Counts the number of occurence of a speficied character in a string.
|
|
|
|
* @param string the character sequence to search into.
|
|
|
|
* @param character the character to count.
|
|
|
|
* @return the number of occurence of
|
|
|
|
* @deprecated Because it uses snake_case naming convention. Use {@link #countOccurences(CharSequence, char)} instead.
|
|
|
|
*/
|
|
|
|
@Deprecated(forRemoval = true, since = "2022-07-26")
|
|
|
|
public static int char_count(CharSequence string, char character) {
|
|
|
|
return countOccurences(string, character);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Counts the number of occurence of a speficied character in a string.
|
|
|
|
* @param string the character sequence to search into.
|
|
|
|
* @param character the character to count.
|
|
|
|
* @return the number of occurence of
|
2016-02-16 20:07:51 +01:00
|
|
|
*/
|
2022-07-28 01:13:35 +02:00
|
|
|
public static int countOccurences(CharSequence string, char character) {
|
2016-02-16 20:07:51 +01:00
|
|
|
int count = 0;
|
2022-07-28 01:13:35 +02:00
|
|
|
for (char c : string.toString().toCharArray()) {
|
|
|
|
if (c == character) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
2016-02-16 20:07:51 +01:00
|
|
|
return count;
|
|
|
|
}
|
2022-07-28 01:13:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do like {@link String#join(CharSequence, Iterable)}, but the last separator is different than the others.
|
|
|
|
* It is usedful when enumerating thins in a sentense, for instance : <code>"a thing<u>, </u>a thing<u> and </u>a thing"</code>
|
|
|
|
* (the coma being the usual separator, and {@code " and "} being the final separator).
|
|
|
|
* @param regularSeparator the separator used everywhere except between the two last strings to join.
|
|
|
|
* @param finalSeparator the separator used between the two last strings to join.
|
|
|
|
* @param strings the strings to join.
|
|
|
|
* @return a new string will all the provided {@code strings} joined using the separators.
|
|
|
|
*/
|
|
|
|
public static String joinGrammatically(CharSequence regularSeparator, CharSequence finalSeparator, List<String> strings) {
|
2018-07-21 17:57:44 +02:00
|
|
|
int size = strings == null ? 0 : strings.size();
|
2022-07-28 01:13:35 +02:00
|
|
|
return switch (size) {
|
|
|
|
case 0 -> "";
|
|
|
|
case 1 -> strings.get(0);
|
|
|
|
default -> String.join(regularSeparator, strings.subList(0, --size)) + finalSeparator + strings.get(size);
|
|
|
|
};
|
2018-07-21 17:57:44 +02:00
|
|
|
}
|
2022-07-28 01:13:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a {@link String} that repeats the base character n times.
|
|
|
|
* @param base the base character.
|
|
|
|
* @param n the number of repetition.
|
|
|
|
* @return a {@link String} that repeats the base character n times.
|
|
|
|
*/
|
|
|
|
public static String repeat(char base, int n) {
|
|
|
|
char[] chars = new char[n];
|
2021-08-15 03:24:56 +02:00
|
|
|
Arrays.fill(chars, base);
|
2022-07-28 01:13:35 +02:00
|
|
|
return String.valueOf(chars);
|
2020-04-06 00:10:14 +02:00
|
|
|
}
|
2022-08-13 00:55:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Pattern endingNumber = Pattern.compile("(\\d+)$");
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a name based on the original name, but that does not conflit with anouther one, according to the
|
|
|
|
* provided predicate.
|
|
|
|
* It can be used to to add an entry in a map when the key already exists, and it is ok to modify the added key to
|
|
|
|
* not erase the previous data.
|
|
|
|
* This situation can be compared to when a file is added to a directory but another file with the same name exists,
|
|
|
|
* so the new file have a suffix number to make the file name different.
|
|
|
|
* <p>
|
|
|
|
* Be aware that this method may run an infinite loop if the predicate continuously returns true.
|
|
|
|
* @param originalName the original conflicting name.
|
|
|
|
* @param conflictTester a predicate that test if a generated name stills conflict with a set of name
|
|
|
|
* @return the original name, with a suffix number (ex: {@code "original1"}).
|
|
|
|
*/
|
|
|
|
public static String fixConflictName(String originalName, Predicate<String> conflictTester) {
|
|
|
|
int suffix = 1;
|
|
|
|
Matcher endingMatcher = endingNumber.matcher(originalName);
|
|
|
|
if (endingMatcher.find()) {
|
|
|
|
suffix = Integer.parseInt(endingMatcher.group(1)) + 1;
|
|
|
|
originalName = originalName.substring(0, endingMatcher.start());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;; suffix++) {
|
|
|
|
String newStr = originalName + suffix;
|
|
|
|
if (!conflictTester.test(newStr))
|
|
|
|
return newStr;
|
|
|
|
}
|
|
|
|
}
|
2022-08-14 00:29:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wraps the provided {@link UnaryOperator} of integer into an {@link UnaryOperator} of String parsing the input
|
|
|
|
* string to int and converting back the return value to String.
|
|
|
|
* @param operator the {@link UnaryOperator} to warp.
|
|
|
|
* @return an {@link UnaryOperator} of String.
|
|
|
|
*/
|
|
|
|
public static UnaryOperator<String> wrapParsingInt(UnaryOperator<Integer> operator) {
|
|
|
|
return s -> Integer.toString(operator.apply(Integer.parseInt(s)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wraps the provided {@link UnaryOperator} of long into an {@link UnaryOperator} of String parsing the input
|
|
|
|
* string to long and converting back the return value to String.
|
|
|
|
* @param operator the {@link UnaryOperator} to warp.
|
|
|
|
* @return an {@link UnaryOperator} of String.
|
|
|
|
*/
|
|
|
|
public static UnaryOperator<String> wrapParsingLong(UnaryOperator<Long> operator) {
|
|
|
|
return s -> Long.toString(operator.apply(Long.parseLong(s)));
|
|
|
|
}
|
|
|
|
|
2016-02-16 20:07:51 +01:00
|
|
|
}
|