Skip to content

Instantly share code, notes, and snippets.

@pygman
Created September 18, 2016 02:32
Show Gist options
  • Save pygman/54f8e9a3906fc1410c6a42eed3db6eca to your computer and use it in GitHub Desktop.
Save pygman/54f8e9a3906fc1410c6a42eed3db6eca to your computer and use it in GitHub Desktop.
Strman Java字符串处理库 学习
/*
*
* * The MIT License
* *
* * Copyright 2016 Shekhar Gulati <[email protected]>.
* *
* * Permission is hereby granted, free of charge, to any person obtaining a copy
* * of this software and associated documentation files (the "Software"), to deal
* * in the Software without restriction, including without limitation the rights
* * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* * copies of the Software, and to permit persons to whom the Software is
* * furnished to do so, subject to the following conditions:
* *
* * The above copyright notice and this permission notice shall be included in
* * all copies or substantial portions of the Software.
* *
* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* * THE SOFTWARE.
*
*/
package strman;
import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import static java.util.stream.Collectors.joining;
/**
* A String manipulation library without any dependencies
*/
public abstract class Strman {
private static final Predicate<String> NULL_STRING_PREDICATE = str -> str == null;
private static final Supplier<String> NULL_STRING_MSG_SUPPLIER = () -> "'value' should be not null.";
private Strman() {
}
/**
* Appends Strings to value
*
* @param value initial String
* @param appends an array of strings to append
* @return full String
*/
public static String append(final String value, final String... appends) {
return appendArray(value, appends);
}
/**
* Append an array of String to value
*
* @param value initial String
* @param appends an array of strings to append
* @return full String
*/
public static String appendArray(final String value, final String[] appends) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (appends == null || appends.length == 0) {
return value;
}
StringJoiner joiner = new StringJoiner("");
for (String append : appends) {
joiner.add(append);
}
return value + joiner.toString();
}
/**
* Get the character at index. This method will take care of negative indexes.
* The valid value of index is between -(length-1) to (length-1).
* For values which don't fall under this range Optional.empty will be returned.
*
* @param value input value
* @param index location
* @return an Optional String if found else empty
*/
public static Optional<String> at(final String value, int index) {
if (value == null || value.isEmpty()) {
return Optional.empty();
}
int length = value.length();
if (index < 0) {
index = length + index;
}
return (index < length && index >= 0) ? Optional.of(String.valueOf(value.charAt(index))) : Optional.empty();
}
/**
* Returns an array with strings between start and end.
*
* @param value input
* @param start start
* @param end end
* @return Array containing different parts between start and end.
*/
public static String[] between(final String value, final String start, final String end) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
validate(start, NULL_STRING_PREDICATE, () -> "'start' should be not null.");
validate(end, NULL_STRING_PREDICATE, () -> "'end' should be not null.");
String[] parts = value.split(end);
return Arrays.stream(parts).map(subPart -> subPart.substring(subPart.indexOf(start) + start.length())).toArray(String[]::new);
}
/**
* Returns a String array consisting of the characters in the String.
*
* @param value input
* @return character array
*/
public static String[] chars(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.split("");
}
/**
* Replace consecutive whitespace characters with a single space.
*
* @param value input String
* @return collapsed String
*/
public static String collapseWhitespace(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.trim().replaceAll("\\s\\s+", " ");
}
/**
* Verifies that the needle is contained in the value. The search is case insensitive
*
* @param value to search
* @param needle to find
* @return true if found else false.
*/
public static boolean contains(final String value, final String needle) {
return contains(value, needle, false);
}
/**
* Verifies that the needle is contained in the value.
*
* @param value to search
* @param needle to find
* @param caseSensitive true or false
* @return true if found else false.
*/
public static boolean contains(final String value, final String needle, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (caseSensitive) {
return value.contains(needle);
}
return value.toLowerCase().contains(needle.toLowerCase());
}
/**
* Verifies that all needles are contained in value. The search is case insensitive
*
* @param value input String to search
* @param needles needles to find
* @return true if all needles are found else false.
*/
public static boolean containsAll(final String value, final String[] needles) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return Arrays.stream(needles).allMatch(needle -> contains(value, needle, true));
}
/**
* Verifies that all needles are contained in value
*
* @param value input String to search
* @param needles needles to find
* @param caseSensitive true or false
* @return true if all needles are found else false.
*/
public static boolean containsAll(final String value, final String[] needles, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return Arrays.stream(needles).allMatch(needle -> contains(value, needle, caseSensitive));
}
/**
* Verifies that one or more of needles are contained in value. This is case insensitive
*
* @param value input
* @param needles needles to search
* @return boolean true if any needle is found else false
*/
public static boolean containsAny(final String value, final String[] needles) {
return containsAny(value, needles, false);
}
/**
* Verifies that one or more of needles are contained in value.
*
* @param value input
* @param needles needles to search
* @param caseSensitive true or false
* @return boolean true if any needle is found else false
*/
public static boolean containsAny(final String value, final String[] needles, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return Arrays.stream(needles).anyMatch(needle -> contains(value, needle, caseSensitive));
}
/**
* Count the number of times substr appears in value
*
* @param value input
* @param subStr to search
* @return count of times substring exists
*/
public static long countSubstr(final String value, final String subStr) {
return countSubstr(value, subStr, true, false);
}
/**
* Count the number of times substr appears in value
*
* @param value input
* @param subStr search string
* @param caseSensitive whether search should be case sensitive
* @param allowOverlapping boolean to take into account overlapping
* @return count of times substring exists
*/
public static long countSubstr(final String value, final String subStr, final boolean caseSensitive, boolean allowOverlapping) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return countSubstr(caseSensitive ? value : value.toLowerCase(), caseSensitive ? subStr : subStr.toLowerCase(), allowOverlapping, 0L);
}
/**
* Test if value ends with search. The search is case sensitive.
*
* @param value input string
* @param search string to search
* @return true or false
*/
public static boolean endsWith(final String value, final String search) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return endsWith(value, search, value.length(), true);
}
/**
* Test if value ends with search.
*
* @param value input string
* @param search string to search
* @param caseSensitive true or false
* @return true or false
*/
public static boolean endsWith(final String value, final String search, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return endsWith(value, search, value.length(), caseSensitive);
}
/**
* Test if value ends with search.
*
* @param value input string
* @param search string to search
* @param position position till which you want to search.
* @param caseSensitive true or false
* @return true or false
*/
public static boolean endsWith(final String value, final String search, final int position, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
int remainingLength = position - search.length();
if (caseSensitive) {
return value.indexOf(search, remainingLength) > -1;
}
return value.toLowerCase().indexOf(search.toLowerCase(), remainingLength) > -1;
}
/**
* Ensures that the value begins with prefix. If it doesn't exist, it's prepended. It is case sensitive.
*
* @param value input
* @param prefix prefix
* @return string with prefix if it was not present.
*/
public static String ensureLeft(final String value, final String prefix) {
return ensureLeft(value, prefix, true);
}
/**
* Ensures that the value begins with prefix. If it doesn't exist, it's prepended.
*
* @param value input
* @param prefix prefix
* @param caseSensitive true or false
* @return string with prefix if it was not present.
*/
public static String ensureLeft(final String value, final String prefix, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (caseSensitive) {
return value.startsWith(prefix) ? value : prefix + value;
}
String _value = value.toLowerCase();
String _prefix = prefix.toLowerCase();
return _value.startsWith(_prefix) ? value : prefix + value;
}
/**
* Decodes data encoded with MIME base64
*
* @param value The data to decode
* @return decoded data
*/
public static String base64Decode(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return new String(Base64.getDecoder().decode(value));
}
/**
* Encodes data with MIME base64.
*
* @param value The data to encode
* @return The encoded String
*/
public static String base64Encode(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return Base64.getEncoder().encodeToString(value.getBytes());
}
/**
* Convert binary unicode (16 digits) string to string chars
*
* @param value The value to decode
* @return The decoded String
*/
public static String binDecode(final String value) {
return decode(value, 16, 2);
}
/**
* Convert string chars to binary unicode (16 digits)
*
* @param value The value to encode
* @return String in binary format
*/
public static String binEncode(final String value) {
return encode(value, 16, 2);
}
/**
* Convert decimal unicode (5 digits) string to string chars
*
* @param value The value to decode
* @return decoded String
*/
public static String decDecode(final String value) {
return decode(value, 5, 10);
}
/**
* Convert string chars to decimal unicode (5 digits)
*
* @param value The value to encode
* @return Encoded value
*/
public static String decEncode(final String value) {
return encode(value, 5, 10);
}
/**
* Ensures that the value ends with suffix. If it doesn't, it's appended. This operation is case sensitive.
*
* @param value The input String
* @param suffix The substr to be ensured to be right
* @return The string which is guarenteed to start with substr
*/
public static String ensureRight(final String value, final String suffix) {
return ensureRight(value, suffix, true);
}
/**
* Ensures that the value ends with suffix. If it doesn't, it's appended.
*
* @param value The input String
* @param suffix The substr to be ensured to be right
* @param caseSensitive Use case (in-)sensitive matching for determining if value already ends with suffix
* @return The string which is guarenteed to start with substr
*/
public static String ensureRight(final String value, final String suffix, boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return endsWith(value, suffix, caseSensitive) ? value : append(value, suffix);
}
/**
* Returns the first n chars of String
*
* @param value The input String
* @param n Number of chars to return
* @return The first n chars
*/
public static String first(final String value, final int n) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.substring(0, n);
}
/**
* Return the first char of String
*
* @param value The input String
* @return The first char
*/
public static String head(final String value) {
return first(value, 1);
}
/**
* Formats a string using parameters
*
* @param value The value to be formatted
* @param params Parameters to be described in the string
* @return The formatted string
*/
public static String format(final String value, String... params) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
Pattern p = Pattern.compile("\\{(\\w+)\\}");
Matcher m = p.matcher(value);
String result = value;
while (m.find()) {
int paramNumber = Integer.parseInt(m.group(1));
if (params == null || paramNumber >= params.length) {
throw new IllegalArgumentException("params does not have value for " + m.group());
}
result = result.replace(m.group(), params[paramNumber]);
}
return result;
}
/**
* Convert hexadecimal unicode (4 digits) string to string chars
*
* @param value The value to decode
* @return The decoded String
*/
public static String hexDecode(final String value) {
return decode(value, 4, 16);
}
/**
* Convert string chars to hexadecimal unicode (4 digits)
*
* @param value The value to encode
* @return String in hexadecimal format.
*/
public static String hexEncode(final String value) {
return encode(value, 4, 16);
}
/**
* The indexOf() method returns the index within the calling String of the first occurrence of the specified value, starting the search at fromIndex.
* Returns -1 if the value is not found.
*
* @param value The input String
* @param needle The search String
* @param offset The offset to start searching from.
* @param caseSensitive boolean to indicate whether search should be case sensitive
* @return Returns position of first occurrence of needle.
*/
public static int indexOf(final String value, final String needle, int offset, boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (caseSensitive) {
return value.indexOf(needle, offset);
}
return value.toLowerCase().indexOf(needle.toLowerCase(), offset);
}
/**
* Tests if two Strings are inequal
*
* @param first The first String
* @param second The second String
* @return true if first and second are not equal false otherwise
*/
public static boolean unequal(final String first, final String second) {
return !Objects.equals(first, second);
}
/**
* Tests if two Strings are inequal
*
* @param first The first String
* @param second The second String
* @return true if first and second are not equal false otherwise
* @deprecated use unequal instead
*/
public static boolean inequal(final String first, final String second) {
return !Objects.equals(first, second);
}
/**
* Inserts 'substr' into the 'value' at the 'index' provided.
*
* @param value The input String
* @param substr The String to insert
* @param index The index to insert substr
* @return String with substr added
*/
public static String insert(final String value, final String substr, final int index) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
validate(substr, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (index > value.length()) {
return value;
}
return append(value.substring(0, index), substr, value.substring(index));
}
/**
* Verifies if String is uppercase
*
* @param value The input String
* @return true if String is uppercase false otherwise
*/
public static boolean isUpperCase(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
for (int i = 0; i < value.length(); i++) {
if (Character.isLowerCase(value.charAt(i))) {
return false;
}
}
return true;
}
/**
* Verifies if String is lower case
*
* @param value The input String
* @return true if String is lowercase false otherwise
*/
public static boolean isLowerCase(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
for (int i = 0; i < value.length(); i++) {
if (Character.isUpperCase(value.charAt(i))) {
return false;
}
}
return true;
}
/**
* Return the last n chars of String
*
* @param value The input String
* @param n Number of chars to return
* @return n Last characters
*/
public static String last(final String value, int n) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (n > value.length()) {
return value;
}
return value.substring(value.length() - n);
}
/**
* Returns a new string of a given length such that the beginning of the string is padded.
*
* @param value The input String
* @param pad The pad
* @param length Length of the String we want
* @return Padded String
*/
public static String leftPad(final String value, final String pad, final int length) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
validate(pad, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (value.length() > length) {
return value;
}
return append(repeat(pad, length - value.length()), value);
}
/**
* Checks whether Object is String
*
* @param value The input String
* @return true if Object is a String false otherwise
*/
public static boolean isString(final Object value) {
if (Objects.isNull(value)) {
throw new IllegalArgumentException("value can't be null");
}
return value instanceof String;
}
/**
* This method returns the index within the calling String object of the last occurrence of the specified value, searching backwards from the offset.
* Returns -1 if the value is not found. The search starts from the end and case sensitive.
*
* @param value The input String
* @param needle The search String
* @return Return position of the last occurrence of 'needle'.
*/
public static int lastIndexOf(final String value, final String needle) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return lastIndexOf(value, needle, value.length(), true);
}
/**
* This method returns the index within the calling String object of the last occurrence of the specified value, searching backwards from the offset.
* Returns -1 if the value is not found. The search starts from the end and case sensitive.
*
* @param value The input String
* @param needle The search String
* @param caseSensitive true or false
* @return Return position of the last occurrence of 'needle'.
*/
public static int lastIndexOf(final String value, final String needle, boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return lastIndexOf(value, needle, value.length(), caseSensitive);
}
/**
* This method returns the index within the calling String object of the last occurrence of the specified value, searching backwards from the offset.
* Returns -1 if the value is not found.
*
* @param value The input String
* @param needle The search String
* @param offset The index to start search from
* @param caseSensitive whether search should be case sensitive
* @return Return position of the last occurrence of 'needle'.
*/
public static int lastIndexOf(final String value, final String needle, final int offset, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
validate(needle, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (caseSensitive) {
return value.lastIndexOf(needle, offset);
}
return value.toLowerCase().lastIndexOf(needle.toLowerCase(), offset);
}
/**
* Removes all spaces on left
*
* @param value The input String
* @return String without left border spaces
*/
public static String leftTrim(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.replaceAll("^\\s+", "");
}
/**
* Returns length of String. Delegates to java.lang.String length method.
*
* @param value The input String
* @return Length of the String
*/
public static int length(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.length();
}
/**
* Return a new String starting with prepends
*
* @param value The input String
* @param prepends Strings to prepend
* @return The prepended String
*/
public static String prepend(final String value, final String... prepends) {
return prependArray(value, prepends);
}
/**
* Return a new String starting with prepends
*
* @param value The input String
* @param prepends Strings to prepend
* @return The prepended String
*/
public static String prependArray(final String value, final String[] prepends) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (prepends == null || prepends.length == 0) {
return value;
}
StringJoiner joiner = new StringJoiner("");
for (String prepend : prepends) {
joiner.add(prepend);
}
return joiner.toString() + value;
}
/**
* Remove empty Strings from string array
*
* @param strings Array of String to be cleaned
* @return Array of String without empty Strings
*/
public static String[] removeEmptyStrings(String[] strings) {
if (Objects.isNull(strings)) {
throw new IllegalArgumentException("Input array should not be null");
}
return Arrays.stream(strings).filter(str -> str != null && !str.trim().isEmpty()).toArray(String[]::new);
}
/**
* Returns a new String with the prefix removed, if present. This is case sensitive.
*
* @param value The input String
* @param prefix String to remove on left
* @return The String without prefix
*/
public static String removeLeft(final String value, final String prefix) {
return removeLeft(value, prefix, true);
}
/**
* Returns a new String with the prefix removed, if present.
*
* @param value The input String
* @param prefix String to remove on left
* @param caseSensitive ensure case sensitivity
* @return The String without prefix
*/
public static String removeLeft(final String value, final String prefix, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
validate(prefix, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (caseSensitive) {
return value.startsWith(prefix) ? value.substring(prefix.length()) : value;
}
return value.toLowerCase().startsWith(prefix.toLowerCase()) ? value.substring(prefix.length()) : value;
}
/**
* Remove all non word characters.
*
* @param value The input String
* @return String without non-word characters
*/
public static String removeNonWords(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.replaceAll("[^\\w]+", "");
}
/**
* Returns a new string with the 'suffix' removed, if present. Search is case sensitive.
*
* @param value The input String
* @param suffix The suffix to remove
* @return The String without suffix!
*/
public static String removeRight(final String value, final String suffix) {
return removeRight(value, suffix, true);
}
/**
* Returns a new string with the 'suffix' removed, if present.
*
* @param value The input String
* @param suffix The suffix to remove
* @param caseSensitive whether search should be case sensitive or not
* @return The String without suffix!
*/
public static String removeRight(final String value, final String suffix, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
validate(suffix, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return endsWith(value, suffix, caseSensitive) ? value.substring(0, value.toLowerCase().lastIndexOf(suffix.toLowerCase())) : value;
}
/**
* Remove all spaces and replace for value.
*
* @param value The input String
* @return String without spaces
*/
public static String removeSpaces(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.replaceAll("\\s", "");
}
/**
* Returns a repeated string given a multiplier.
*
* @param value The input String
* @param multiplier Number of repeats
* @return The String repeated
*/
public static String repeat(final String value, final int multiplier) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return Stream.generate(() -> value).limit(multiplier).collect(joining());
}
/**
* Replace all occurrences of 'search' value to 'newvalue'. Uses String replace method.
*
* @param value The input
* @param search The String to search
* @param newValue The String to replace
* @param caseSensitive whether search should be case sensitive or not
* @return String replaced with 'newvalue'.
*/
public static String replace(final String value, final String search, final String newValue, final boolean caseSensitive) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
validate(search, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (caseSensitive) {
return value.replace(search, newValue);
}
return Pattern.compile(search, Pattern.CASE_INSENSITIVE).matcher(value).replaceAll(Matcher.quoteReplacement(newValue));
}
/**
* Reverse the input String
*
* @param value The input String
* @return Reversed String
*/
public static String reverse(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return new StringBuilder(value).reverse().toString();
}
/**
* Returns a new string of a given length such that the ending of the string is padded.
*
* @param value The input String
* @param length Max length of String.
* @param pad Character to repeat
* @return Right padded String
*/
public static String rightPad(final String value, String pad, final int length) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (value.length() > length) {
return value;
}
return append(value, repeat(pad, length - value.length()));
}
/**
* Remove all spaces on right.
*
* @param value The String
* @return String without right boarders spaces.
*/
public static String rightTrim(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.replaceAll("\\s+$", "");
}
/**
* Truncate the string securely, not cutting a word in half. It always returns the last full word.
*
* @param value The input String
* @param length Max size of the truncated String
* @param filler String that will be added to the end of the return string. Example: '...'
* @return The truncated String
*/
public static String safeTruncate(final String value, final int length, final String filler) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (length == 0) {
return "";
}
if (length >= value.length()) {
return value;
}
String[] words = words(value);
StringJoiner result = new StringJoiner(" ");
int spaceCount = 0;
for (String word : words) {
if (result.length() + word.length() + filler.length() + spaceCount > length) {
break;
} else {
result.add(word);
spaceCount++;
}
}
return append(result.toString(), filler);
}
/**
* Alias to String split function. Defined only for completeness.
*
* @param value The input String
* @param regex The delimiting regular expression
* @return String Array
*/
public static String[] split(final String value, final String regex) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.split(regex);
}
/**
* Splits a String to words
*
* @param value The input String
* @return Words Array
*/
public static String[] words(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.split("\\W+");
}
/**
* Truncate the unsecured form string, cutting the independent string of required position.
*
* @param value Value will be truncated unsecurely.
* @param length Size of the returned string.
* @param filler Value that will be added to the end of the return string. Example: '...'
* @return String truncated unsafely.
*/
public static String truncate(final String value, final int length, final String filler) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
if (length == 0) {
return "";
}
if (length >= value.length()) {
return value;
}
return append(value.substring(0, length - filler.length()), filler);
}
/**
* Converts all HTML entities to applicable characters.
*
* @param encodedHtml The encoded HTML
* @return The decoded HTML
*/
public static String htmlDecode(final String encodedHtml) {
validate(encodedHtml, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
String[] entities = encodedHtml.split("&\\W+;");
return Arrays.stream(entities).map(e -> HtmlEntities.decodedEntities.get(e)).collect(joining());
}
/**
* Convert all applicable characters to HTML entities.
*
* @param html The HTML to encode
* @return The encoded data
*/
public static String htmlEncode(final String html) {
validate(html, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return html.chars().mapToObj(c -> "\\u" + String.format("%04x", c).toUpperCase()).map(e -> HtmlEntities.encodedEntities.get(e)).collect(joining());
}
/**
* It returns a string with its characters in random order.
*
* @param value The input String
* @return The shuffled String
*/
public static String shuffle(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
String[] chars = chars(value);
Random random = new Random();
for (int i = 0; i < chars.length; i++) {
int r = random.nextInt(chars.length);
String tmp = chars[i];
chars[i] = chars[r];
chars[r] = tmp;
}
return Arrays.stream(chars).collect(joining());
}
/**
* Alias of substring method
*
* @param value The input String
* @param begin Start of slice.
* @param end End of slice.
* @return The String sliced!
*/
public static String slice(final String value, int begin, int end) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.substring(begin, end);
}
/**
* Convert a String to a slug
*
* @param value The value to slugify
* @return The slugified value
*/
public static String slugify(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
String transliterated = transliterate(collapseWhitespace(value.trim().toLowerCase()));
return Arrays.stream(words(transliterated.replace("&", "-and-"))).collect(joining("-"));
}
/**
* Remove all non valid characters.
*
* @param value The input String
* @return String without non valid characters.
*/
public static String transliterate(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
String result = value;
Set<Map.Entry<String, List<String>>> entries = Ascii.ascii.entrySet();
for (Map.Entry<String, List<String>> entry : entries) {
for (String ch : entry.getValue()) {
result = result.replace(ch, entry.getKey());
}
}
return result;
}
/**
* Surrounds a 'value' with the given 'prefix' and 'suffix'.
*
* @param value The input String
* @param prefix prefix. If suffix is null then prefix is used
* @param suffix suffix
* @return The String with surround substrs!
*/
public static String surround(final String value, final String prefix, final String suffix) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
String _prefix = Optional.ofNullable(prefix).orElse("");
return append(_prefix, value, Optional.ofNullable(suffix).orElse(_prefix));
}
/**
* Transform to camelCase
*
* @param value The input String
* @return String in camelCase.
*/
public static String toCamelCase(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
String str = toStudlyCase(value);
return str.substring(0, 1).toLowerCase() + str.substring(1);
}
/**
* Transform to StudlyCaps.
*
* @param value The input String
* @return String in StudlyCaps.
*/
public static String toStudlyCase(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
String[] words = collapseWhitespace(value.trim()).split("\\s*(_|-|\\s)\\s*");
return Arrays.stream(words).filter(w -> !w.trim().isEmpty()).map(w -> head(w).toUpperCase() + tail(w)).collect(joining());
}
/**
* Return tail of the String
*
* @param value The input String
* @return String tail
*/
public static String tail(final String value) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return last(value, value.length() - 1);
}
/**
* Decamelize String
*
* @param value The input String
* @param chr string to use
* @return String decamelized.
*/
public static String toDecamelize(final String value, final String chr) {
String camelCasedString = toCamelCase(value);
String[] words = camelCasedString.split("(?=\\p{Upper})");
return Arrays.stream(words).map(String::toLowerCase).collect(joining(Optional.ofNullable(chr).orElse(" ")));
}
/**
* Transform to kebab-case.
*
* @param value The input String
* @return String in kebab-case.
*/
public static String toKebabCase(final String value) {
return toDecamelize(value, "-");
}
/**
* Transform to snake_case.
*
* @param value The input String
* @return String in snake_case.
*/
public static String toSnakeCase(final String value) {
return toDecamelize(value, "_");
}
public static String decode(final String value, final int digits, final int radix) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return Arrays
.stream(value.split("(?<=\\G.{" + digits + "})"))
.map(data -> String.valueOf(Character.toChars(Integer.parseInt(data, radix))))
.collect(joining());
}
public static String encode(final String value, final int digits, final int radix) {
validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER);
return value.chars().mapToObj(ch -> leftPad(Integer.toString(ch, radix), "0", digits)).collect(joining());
}
private static void validate(String value, Predicate<String> predicate, final Supplier<String> supplier) {
if (predicate.test(value)) {
throw new IllegalArgumentException(supplier.get());
}
}
private static long countSubstr(String value, String subStr, boolean allowOverlapping, long count) {
int position = value.indexOf(subStr);
if (position == -1) {
return count;
}
int offset;
if (!allowOverlapping) {
offset = position + subStr.length();
} else {
offset = position + 1;
}
return countSubstr(value.substring(offset), subStr, allowOverlapping, ++count);
}
}
import strman.Strman;
import java.util.Arrays;
import java.util.Optional;
public class StrmanTest {
public static void main(String[] args) {
// append 在一个字符串后追加任意个数的字符串
String s1 = Strman.append("f", "o", "o", "b", "a", "r");
System.out.println("append:" + s1); // result => "foobar"
// prepend 在一个字符串前追加任意个数的字符串
String s1pre = Strman.prepend("r", "f", "o", "o", "b", "a");
System.out.println("prepend:" + s1pre); // result => "foobar"
// appendArray 在一个字符串后先后追加一个字符串数组中的元素
String s2 = Strman.appendArray("f", new String[]{"o", "o", "b", "a", "r"});
System.out.println("append:" + s2); // result => "foobar"
// at 根据字符串的索引获取到对应的字符。如果索引是负数,则逆向获取,超出则抛出异常
Optional<String> s3 = Strman.at("foobar", 3);
System.out.println("at:" + s3.get()); // result => "b"
// between 得到一个字符串中,开始字符串和结束字符串之间的字符串的数组
String[] s4 = Strman.between("[abc], [def]", "[", "]");
System.out.println("between:" + Arrays.toString(s4)); // result => "[abc, def]"
// chars 得到一个字符串中所有字符构成的字符串数组
String[] s5 = Strman.chars("title");
System.out.println("chars:" + Arrays.toString(s5)); // result => "[t, i, t, l, e]"
// collapseWhitespace 替换掉连续的多个空格为一个空格
String s6 = Strman.collapseWhitespace("foo bar");
System.out.println("chars:" + s6); // result => "foo bar"
// contains 判断一个字符串是否包含另外一个字符串,第三个参数,表示字符串大小写是否敏感
boolean s7 = Strman.contains("foo bar", "foo");
boolean s8 = Strman.contains("foo bar", "FOO", false);
System.out.println("contains:" + s7 + ", " + s8); // result => "true, true"
// containsAll 判断一个字符串是否包含某字符串数组中的所有元素
boolean s9 = Strman.containsAll("foo bar", new String[]{"foo", "bar"});
boolean s10 = Strman.containsAll("foo bar", new String[]{"FOO", "bar"}, false);
System.out.println("containsAll:" + s9 + ", " + s10); // result => "true, true"
// containsAny 判断一个字符串是否包含某字符串数组中的任意一个元素
boolean s11 = Strman.containsAny("foo bar", new String[]{"FOO", "BAR", "Test"}, false);
System.out.println("containsAny:" + s11); // result => "true"
// countSubstr 判断一个字符串包含某字符串的个数
long s12 = Strman.countSubstr("aaaAAAaaa", "aaa");
long s13 = Strman.countSubstr("aaaAAAaaa", "aaa", false, false);
System.out.println("countSubstr:" + s12 + ", " + s13); // result => "2, 3"
// endsWith 判断一个字符串是否以某个字符串结尾
boolean s14 = Strman.endsWith("foo bar", "bar");
boolean s15 = Strman.endsWith("foo bar", "BAR", false);
System.out.println("endsWith:" + s14 + ", " + s15); // result => "true, true"
// ensureLeft 确保一个字符串以某个字符串开头,如果不是,则在前面追加该字符串,并将字符串结果返回
String s16 = Strman.ensureLeft("foobar", "foo");
String s17 = Strman.ensureLeft("bar", "foo");
String s18 = Strman.ensureLeft("foobar", "FOO", false);
System.out.println("ensureLeft:" + s16 + ", " + s17 + ", " + s18);
// result => "foobar, foobar, foobar"
// ensureRight 确保一个字符串以某个字符串开头,如果不是,则在前面追加该字符串,并将字符串结果返回
String s16r = Strman.ensureRight("foobar", "bar");
String s17r = Strman.ensureRight("foo", "bar");
String s18r = Strman.ensureRight("fooBAR", "bar", false);
System.out.println("ensureRight:" + s16r + ", " + s17r + ", " + s18r);
// result => "foobar, foobar, fooBAR"
// base64Encode 将字符串转成Base64编码的字符串
String s19 = Strman.base64Encode("strman");
System.out.println("base64Encode:" + s19); // result => "c3RybWFu"
// binDecode 将二进制编码(16位)转成字符串字符
String s20 = Strman.binDecode("0000000001000001");
System.out.println("binDecode:" + s20); // result => "A"
// binEncode 将字符串字符转成二进制编码(16位)
String s21 = Strman.binEncode("A");
System.out.println("binEncode:" + s21); // result => "0000000001000001"
// decDecode 将十进制编码(5位)转成字符串字符
String s22 = Strman.decDecode("00065");
System.out.println("decDecode:" + s22); // result => "A"
// decEncode 将字符串转成十进制编码(5位)
String s23 = Strman.decEncode("A");
System.out.println("decEncode:" + s23); // result => "00065"
// first 得到从字符串开始到索引n的字符串
String s24 = Strman.first("foobar", 3);
System.out.println("first:" + s24); // result => "foo"
// last 得到从字符串结尾倒数索引n的字符串
String s24l = Strman.last("foobar", 3);
System.out.println("last:" + s24l); // result => "bar"
// head 得到字符串的第一个字符
String s25 = Strman.head("foobar");
System.out.println("head:" + s25); // result => "f"
// hexDecode 将字符串字符转成十六进制编码(4位)
String s26 = Strman.hexDecode("0041");
System.out.println("hexDecode:" + s26); // result => "A"
// hexEncode 将十六进制编码(4位)转成字符串字符
String s27 = Strman.hexEncode("A");
System.out.println("hexEncode:" + s27); // result => "0041"
// inequal 测试两个字符串是否相等
boolean s28 = Strman.inequal("a", "b");
System.out.println("inequal:" + s28); // result => "true"
// insert 将子字符串插入到字符串某索引位置处
String s29 = Strman.insert("fbar", "oo", 1);
System.out.println("insert:" + s29); // result => "foobar"
// leftPad 将字符串从左补齐直到总长度为n为止
String s30 = Strman.leftPad("1", "0", 5);
System.out.println("leftPad:" + s30); // result => "00001"
// rightPad 将字符串从右补齐直到总长度为n为止
String s30r = Strman.rightPad("1", "0", 5);
System.out.println("rightPad:" + s30r); // result => "10000"
// lastIndexOf 此方法返回在指定值的最后一个发生的调用字符串对象中的索引,从偏移量中向后搜索
int s31 = Strman.lastIndexOf("foobarfoobar", "F", false);
System.out.println("lastIndexOf:" + s31); // result => "6"
// leftTrim 移除字符串最左边的所有空格
String s32 = Strman.leftTrim(" strman ");
System.out.println("leftTrim:" + s32); // result => "strman "
// rightTrim 移除字符串最右边的所有空格
String s32r = Strman.rightTrim(" strman ");
System.out.println("rightTrim:" + s32r); // result => " strman"
// removeEmptyStrings 移除字符串数组中的空字符串
String[] s33 = Strman.removeEmptyStrings(new String[]{"aa", "", " ", "bb", "cc", null});
System.out.println("removeEmptyStrings:" + Arrays.toString(s33));
// result => "[aa, bb, cc]"
// removeLeft 得到去掉前缀(如果存在的话)后的新字符串
String s34 = Strman.removeLeft("foobar", "foo");
System.out.println("removeLeft:" + s34); // result => "bar"
// removeRight 得到去掉后缀(如果存在的话)后的新字符串
String s34r = Strman.removeRight("foobar", "bar");
System.out.println("removeRight:" + s34r); // result => "foo"
// removeNonWords 得到去掉不是字符的字符串
String s35 = Strman.removeNonWords("foo&bar-");
System.out.println("removeNonWords:" + s35); // result => "foobar"
// removeSpaces 移除所有空格
String s36 = Strman.removeSpaces(" str man ");
System.out.println("removeSpaces:" + s36); // result => " strman"
// repeat 得到给定字符串和重复次数的新字符串
String s37 = Strman.repeat("1", 3);
System.out.println("repeat:" + s37); // result => "111"
// reverse 得到反转后的字符串
String s38 = Strman.reverse("foobar");
System.out.println("reverse:" + s38); // result => "raboof"
// safeTruncate 安全的截断字符串,不切一个字的一半,它总是返回最后一个完整的单词
String s39 = Strman.safeTruncate("A Javascript string manipulation library.", 19, "...");
System.out.println("safeTruncate:" + s39); // result => "A Javascript..."
// truncate 不太安全的截断字符串
String s40 = Strman.truncate("A Javascript string manipulation library.", 19, "...");
System.out.println("truncate:" + s40); // result => "A Javascript str..."
// htmlDecode 将html字符反转义
String s41 = Strman.htmlDecode("&SHcy;");
System.out.println("htmlDecode:" + s41); // result => "Ш"
// htmlEncode 将html字符转义
String s42 = Strman.htmlEncode("Ш");
System.out.println("htmlEncode:" + s42); // result => "&SHcy;"
// shuffle 将给定字符串转成随机字符顺序的字符串
String s43 = Strman.shuffle("shekhar");
System.out.println("shuffle:" + s43); // result => "rhsheak"
// slugify 将字符串分段(用"-"分段)
String s44 = Strman.slugify("foo bar");
System.out.println("slugify:" + s44); // result => "foo-bar"
// transliterate 删除所有非有效字符,如:á => a
String s45 = Strman.transliterate("fóõ bár");
System.out.println("transliterate:" + s45); // result => "foo bar"
// surround 给定的“前缀”和“后缀”来包裹一个字符串
String s46 = Strman.surround("div", "<", ">");
System.out.println("surround:" + s46); // result => "<div>"
// tail 得到去掉第一个字符后的字符串
String s47 = Strman.tail("foobar");
System.out.println("tail:" + s47); // result => "oobar"
// toCamelCase 转成驼峰式的字符串
String s48 = Strman.toCamelCase("Camel Case");
String s48_2 = Strman.toCamelCase("camel-case");
System.out.println("tail:" + s48 + ", " + s48_2); // result => "camelCase, camelCase"
// toStudlyCase 转成Studly式的字符串
String s49 = Strman.toStudlyCase("hello world");
System.out.println("toStudlyCase:" + s49); // result => "HelloWorld"
// toDecamelize 转成Decamelize式的字符串
String s50 = Strman.toDecamelize("helloWorld", null);
System.out.println("toDecamelize:" + s50); // result => "hello world"
// toKebabCase 转成Kebab式的字符串
String s51 = Strman.toKebabCase("hello World");
System.out.println("toKebabCase:" + s51); // result => "hello-world"
// toSnakeCase 转成Snake式的字符串
String s52 = Strman.toSnakeCase("hello world");
System.out.println("toSnakeCase:" + s52); // result => "hello_world"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment