ProjectAres/Util/core/src/main/java/tc/oc/commons/core/formatting/StringUtils.java

229 lines
8.5 KiB
Java

package tc.oc.commons.core.formatting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.sk89q.minecraft.util.commands.ChatColor;
import tc.oc.commons.core.LiquidMetal;
public class StringUtils {
public static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 55; // Will never wrap, even with the largest characters
/**
* Shorthand for listToEnglishCompound(list, "", "").
*
* @see #listToEnglishCompound(java.util.Collection, String, String)
*/
public static String listToEnglishCompound(Collection<String> list) {
return listToEnglishCompound(list, "", "");
}
/**
* Converts a list of strings to a nice English list as a string.
* <p/>
* For example: In: ["Anxuiz", "MonsieurApple", "Plastix"] Out: "Anxuiz, MonsieurApple and Plastix"
*
* @param list List of strings to concatenate.
* @param prefix Prefix to add before each element in the resulting string.
* @param suffix Suffix to add after each element in the resulting string.
* @return String version of the list of strings.
*/
public static String listToEnglishCompound(Collection<?> list, String prefix, String suffix) {
StringBuilder builder = new StringBuilder();
int i = 0;
for (Object str : list) {
if (i != 0) {
if (i == list.size() - 1) {
builder.append(" and ");
} else {
builder.append(", ");
}
}
builder.append(prefix).append(str).append(suffix);
i++;
}
return builder.toString();
}
/**
* Shorthand for listToCompound(list, and, "", "").
*
* @see #listToCompound(java.util.Collection, String, String, String)
*/
public static final String listToCompound(Collection<String> list, String and) {
return listToCompound(list, and, "", "");
}
/**
* Converts a list of strings to a nice list as a string.
* <p/>
* For example: In: ["Anxuiz", "MonsieurApple", "Plastix"] Out: "Anxuiz, MonsieurApple {and} Plastix"
*
* @param list List of strings to concatenate.
* @param and String to be used for "and"
* @param prefix Prefix to add before each element in the resulting string.
* @param suffix Suffix to add after each element in the resulting string.
* @return String version of the list of strings.
*/
public static String listToCompound(Collection<?> list, String and, String prefix, String suffix) {
StringBuilder builder = new StringBuilder();
int i = 0;
for (Object str : list) {
if (i != 0) {
if (i == list.size() - 1) {
builder.append(" ").append(and).append(" ");
} else {
builder.append(", ");
}
}
builder.append(prefix).append(str).append(suffix);
i++;
}
return builder.toString();
}
public static @Nullable <T> T bestFuzzyMatch(String query, Iterable<T> choices, double threshold, Function<? super T, String> stringifier) {
T result = null;
for(T choice : choices) {
if(threshold <= LiquidMetal.score(stringifier.apply(choice), query)) {
if(result != null) return null; // multiple matches
result = choice;
}
}
return result;
}
public static @Nullable <T> T bestFuzzyMatch(String search, Iterable<T> choices, double threshold) {
return bestFuzzyMatch(search, choices, threshold, Object::toString);
}
public static @Nullable <T> T bestFuzzyMatch(String query, Map<String, T> choices, double threshold) {
return fuzzyMatch(query, choices, threshold)
.orElse(null);
}
public static <T> Optional<T> fuzzyMatch(String query, Iterable<T> choices, double threshold, Function<? super T, String> stringifier) {
return Optional.ofNullable(bestFuzzyMatch(query, choices, threshold, stringifier));
}
public static <T> Optional<T> fuzzyMatch(String query, Iterable<T> choices, double threshold) {
return fuzzyMatch(query, choices, threshold, Object::toString);
}
public static <T> Optional<T> fuzzyMatch(String query, Map<String, T> choices, double threshold) {
return fuzzyMatch(query, choices.entrySet(), threshold, Map.Entry::getKey)
.map(Map.Entry::getValue);
}
/**
* Sanitizes the provided message, removing any non-alphanumeric characters and swapping spaces with the specified
* string.
* <p/>
* Examples: sanitize("Hello! :) How are you?", '-') --> "Hello--How-are-you" sanitize("I am great, thank you!",
* '*') --> "I*am*great*thank*you"
*
* @param string The message to be sanitized.
* @param spaceReplace The string to be substituted for spaces.
* @return The sanitized string.
*/
public static String sanitize(String string, String spaceReplace) {
return string.replaceAll("[^\\dA-Za-z ]", "").replaceAll("\\s+", spaceReplace);
}
public static String truncate(String text, int length) {
return text.substring(0, Math.min(text.length(), length));
}
public static String removeEnd(String whole, String end) {
return whole.endsWith(end) ? truncate(whole, whole.length() - end.length())
: whole;
}
public static String substring(String text, int begin, int end) {
return text.substring(Math.min(text.length(), begin), Math.min(text.length(), end));
}
public static String dashedChatMessage(String message, String dash, String dashPrefix) {
return dashedChatMessage(message, dash, dashPrefix, null);
}
public static String dashedChatMessage(String message, String dash, String dashPrefix, String messagePrefix) {
message = " " + message + " ";
int dashCount = (GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - ChatColor.stripColor(message).length() - 2) / (dash.length() * 2);
String dashes = dashCount >= 0 ? Strings.repeat(dash, dashCount) : "";
StringBuffer builder = new StringBuffer();
if (dashCount > 0) {
builder.append(dashPrefix).append(dashes).append(ChatColor.RESET);
}
if(messagePrefix != null) {
builder.append(messagePrefix);
}
builder.append(message);
if (dashCount > 0) {
builder.append(ChatColor.RESET).append(dashPrefix).append(dashes);
}
return builder.toString();
}
public static List<String> complete(String prefix, Class<? extends Enum> enumClass) {
return complete(prefix, Stream.of(enumClass.getEnumConstants()).map(c -> c.name().toLowerCase().replace('_', ' ')));
}
public static List<String> complete(String prefix, Collection<String> options) {
return complete(prefix, options.stream());
}
public static List<String> complete(String prefix, Stream<String> options) {
final String prefixLower = prefix.toLowerCase();
final int pos = prefixLower.lastIndexOf(' ');
final List<String> matches = new ArrayList<>();
options.forEach(option -> {
if(option.toLowerCase().startsWith(prefixLower)) {
matches.add(pos == -1 ? option : option.substring(pos + 1));
}
});
Collections.sort(matches);
return matches;
}
public static String slugify(String text, char space) {
return text.trim().toLowerCase().replaceAll("[^a-z0-9" + space + "]+", String.valueOf(space));
}
public static Optional<String> nonEmpty(@Nullable String s) {
return s != null && s.length() > 0 ? Optional.of(s) : Optional.empty();
}
public static String pluralize(String singular) {
// Incredible natural language processing technology
return singular + "s";
}
public static boolean startsWithIgnoreCase(String whole, String prefix) {
return whole.length() >= prefix.length() &&
whole.substring(0, prefix.length()).equalsIgnoreCase(prefix);
}
public static boolean isBlank(@Nullable String s) {
if(s == null) return true;
for(int i = 0; i < s.length(); i++) {
if(!Character.isWhitespace(s.charAt(i))) return false;
}
return true;
}
}