All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ultreia.java4all.lang.Strings Maven / Gradle / Ivy

The newest version!
package io.ultreia.java4all.lang;

/*-
 * #%L
 * Java Lang extends by Ultreia.io
 * %%
 * Copyright (C) 2017 - 2024 Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

/**
 * Created by tchemit on 29/12/2017.
 *
 * @author Tony Chemit - [email protected]
 */
public class Strings {
    public static final String[] EMPTY_STRING_ARRAY = new String[0];
    /**
     * A String for a space character.
     *
     * @since 3.2
     */
    public static final String SPACE = " ";
    public static final String EMPTY = "";
    private static final double[] timeFactors = {1000000, 1000, 60, 60, 24};
    private static final String[] timeUnites = {"ns", "ms", "s", "m", "h", "d"};
    private static final double[] memoryFactors = {1024, 1024, 1024, 1024};
    private static final String[] memoryUnites = {"o", "Ko", "Mo", "Go", "To"};
    private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',};
    /**
     * 

The maximum size to which the padding constant(s) can expand.

*/ private static final int PAD_LIMIT = 8192; /** * Convert a String to SHA1. * * @param toEncode string to encode * @return sha1 corresponding * @throws IllegalStateException if could not found algorithm SHA1 */ public static String encodeSHA1(String toEncode) { try { MessageDigest sha1Md = MessageDigest.getInstance("SHA-1"); byte[] digest = sha1Md.digest(toEncode.getBytes()); return asHex(digest); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException("Can't find SHA-1 message digest algorithm", ex); } } /** * Turns array of bytes into string representing each byte as * unsigned hex number. * * @param hash Array of bytes to convert to hex-string * @return Generated hex string */ private static String asHex(byte hash[]) { char buf[] = new char[hash.length * 2]; for (int i = 0, x = 0; i < hash.length; i++) { buf[x++] = HEX_CHARS[hash[i] >>> 4 & 0xf]; buf[x++] = HEX_CHARS[hash[i] & 0xf]; } return new String(buf); } /** * Converts an time delay into a human readable format. * * @param value the delay to convert * @return the memory representation of the given value * @see #convert(long, double[], String[]) */ public static String convertTime(long value) { return convert(value, timeFactors, timeUnites); } /** * Converts an time period into a human readable format. * * @param value the begin time * @param value2 the end time * @return the time representation of the given value * @see #convert(long, double[], String[]) */ public static String convertTime(long value, long value2) { return convertTime(value2 - value); } /** * Converts an memory measure into a human readable format. * * @param value the memory measure to convert * @return the memory representation of the given value * @see #convert(long, double[], String[]) */ public static String convertMemory(long value) { return convert(value, memoryFactors, memoryUnites); } /** * Note: this method use the current locale (the {@link Locale#getDefault()}) in the method * {@link MessageFormat#MessageFormat(String)}. * * @param value value to convert * @param factors factors used form conversion * @param unites libelle of unites to use * @return the converted representation of the given value */ public static String convert(long value, double[] factors, String[] unites) { long sign = value == 0 ? 1 : value / Math.abs(value); int i = 0; double tmp = Math.abs(value); while (i < factors.length && i < unites.length && tmp > factors[i]) { tmp = tmp / factors[i++]; } tmp *= sign; String result; result = MessageFormat.format("{0,number,0.###}{1}", tmp, unites[i]); return result; } /** * Convertir un nom en une constante Java *

* Les seuls caractères autorisés sont les alpha numériques, ains * que l'underscore. tous les autres caractères seront ignorés. * * @param name le nom à convertir * @return la constante générée */ public static String convertToConstantName(String name) { StringBuilder sb = new StringBuilder(); char lastChar = 0; for (int i = 0, j = name.length(); i < j; i++) { char c = name.charAt(i); if (Character.isDigit(c)) { sb.append(c); lastChar = c; continue; } if (!Character.isLetter(c)) { if (lastChar != '_') { sb.append('_'); } lastChar = '_'; continue; } if (Character.isUpperCase(c)) { if (!Character.isUpperCase(lastChar) && lastChar != '_') { sb.append('_'); } sb.append(c); } else { sb.append(Character.toUpperCase(c)); } lastChar = c; } String result = sb.toString(); // clean tail while (!result.isEmpty() && result.endsWith("_")) { result = result.substring(0, result.length() - 1); } // clean head while (!result.isEmpty() && result.startsWith("_")) { result = result.substring(1); } return result; } /** * Get the relative camel case name for the given {@code fullyQualifiedName}. *

* first try to remove {@code packageName}, then any {@code excludes} on starts, at last reduce with came case. * * @param packageName starts package * @param fullyQualifiedName fqn to transform * @param excludes optional starts packages to remove * @return the camel case result */ public static String getRelativeCamelCaseName(String packageName, String fullyQualifiedName, String... excludes) { String relativeType = removeStart(Objects.requireNonNull(fullyQualifiedName), Objects.requireNonNull(packageName)); for (String exclude : excludes) { relativeType = removeStart(relativeType, "." + exclude); } relativeType = removeStart(relativeType, "."); String[] parts = relativeType.split("\\."); StringBuilder result = new StringBuilder(); for (String part : parts) { result.append(("" + part.charAt(0)).toUpperCase()); result.append(part.substring(1)); } return result.toString(); } /** *

Left pad a String with a specified String.

* *

Pad to a size of {@code size}.

* *
     * Strings.leftPad(null, *, *)      = null
     * Strings.leftPad("", 3, "z")      = "zzz"
     * Strings.leftPad("bat", 3, "yz")  = "bat"
     * Strings.leftPad("bat", 5, "yz")  = "yzbat"
     * Strings.leftPad("bat", 8, "yz")  = "yzyzybat"
     * Strings.leftPad("bat", 1, "yz")  = "bat"
     * Strings.leftPad("bat", -1, "yz") = "bat"
     * Strings.leftPad("bat", 5, null)  = "  bat"
     * Strings.leftPad("bat", 5, "")    = "  bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padStr the String to pad with, null or empty treated as single space * @return left padded String or original String if no padding is necessary, {@code null} if null String input */ public static String leftPad(final String str, final int size, String padStr) { if (str == null) { return null; } if (isEmpty(padStr)) { padStr = SPACE; } final int padLen = padStr.length(); final int strLen = str.length(); final int pads = size - strLen; if (pads <= 0) { return str; // returns original String when possible } if (padLen == 1 && pads <= PAD_LIMIT) { return leftPad(str, size, padStr.charAt(0)); } if (pads == padLen) { return padStr.concat(str); } else if (pads < padLen) { return padStr.substring(0, pads).concat(str); } else { final char[] padding = new char[pads]; final char[] padChars = padStr.toCharArray(); for (int i = 0; i < pads; i++) { padding[i] = padChars[i % padLen]; } return new String(padding).concat(str); } } /** *

Left pad a String with spaces (' ').

* *

The String is padded to the size of {@code size}.

* *
     * Strings.leftPad(null, *)   = null
     * Strings.leftPad("", 3)     = "   "
     * Strings.leftPad("bat", 3)  = "bat"
     * Strings.leftPad("bat", 5)  = "  bat"
     * Strings.leftPad("bat", 1)  = "bat"
     * Strings.leftPad("bat", -1) = "bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @return left padded String or original String if no padding is necessary, {@code null} if null String input */ public static String leftPad(final String str, final int size) { return leftPad(str, size, ' '); } /** *

Left pad a String with a specified character.

* *

Pad to a size of {@code size}.

* *
     * Strings.leftPad(null, *, *)     = null
     * Strings.leftPad("", 3, 'z')     = "zzz"
     * Strings.leftPad("bat", 3, 'z')  = "bat"
     * Strings.leftPad("bat", 5, 'z')  = "zzbat"
     * Strings.leftPad("bat", 1, 'z')  = "bat"
     * Strings.leftPad("bat", -1, 'z') = "bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padChar the character to pad with * @return left padded String or original String if no padding is necessary, {@code null} if null String input */ public static String leftPad(final String str, final int size, final char padChar) { if (str == null) { return null; } final int pads = size - str.length(); if (pads <= 0) { return str; // returns original String when possible } if (pads > PAD_LIMIT) { return leftPad(str, size, String.valueOf(padChar)); } return repeat(padChar, pads).concat(str); } public static boolean isEmpty(String o) { return o == null || o.isEmpty(); } public static boolean isNotEmpty(String o) { return !isEmpty(o); } /** *

Checks if the CharSequence contains only Unicode digits. * A decimal point is not a Unicode digit and returns false.

* *

{@code null} will return {@code false}. * An empty CharSequence (length()=0) will return {@code false}.

* *

Note that the method does not allow for a leading sign, either positive or negative. * Also, if a String passes the numeric test, it may still generate a NumberFormatException * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range * for int or long respectively.

* *
     * Strings.isNumeric(null)   = false
     * Strings.isNumeric("")     = false
     * Strings.isNumeric("  ")   = false
     * Strings.isNumeric("123")  = true
     * Strings.isNumeric("\u0967\u0968\u0969")  = true
     * Strings.isNumeric("12 3") = false
     * Strings.isNumeric("ab2c") = false
     * Strings.isNumeric("12-3") = false
     * Strings.isNumeric("12.3") = false
     * Strings.isNumeric("-123") = false
     * Strings.isNumeric("+123") = false
     * 
* * @param cs the CharSequence to check, may be null * @return {@code true} if only contains digits, and is non-null */ public static boolean isNumeric(String cs) { if (isEmpty(cs)) { return false; } final int sz = cs.length(); for (int i = 0; i < sz; i++) { if (!Character.isDigit(cs.charAt(i))) { return false; } } return true; } /** *

Capitalizes a String changing the first character to title case as * per {@link Character#toTitleCase(int)}. No other characters are changed.

* *
     * Strings.capitalize(null)  = null
     * Strings.capitalize("")    = ""
     * Strings.capitalize("cat") = "Cat"
     * Strings.capitalize("cAt") = "CAt"
     * Strings.capitalize("'cat'") = "'cat'"
     * 
* * @param str the String to capitalize, may be null * @return the capitalized String, {@code null} if null String input */ public static String capitalize(String str) { final int strLen = str == null ? 0 : str.length(); if (strLen == 0) { return str; } final int firstCodepoint = str.codePointAt(0); final int newCodePoint = Character.toTitleCase(firstCodepoint); if (firstCodepoint == newCodePoint) { // already capitalized return str; } final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array int outOffset = 0; newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { final int codepoint = str.codePointAt(inOffset); newCodePoints[outOffset++] = codepoint; // copy the remaining ones inOffset += Character.charCount(codepoint); } return new String(newCodePoints, 0, outOffset); } public static String removeStart(String str, String remove) { if (isEmpty(str) || isEmpty(remove)) { return str; } if (str.startsWith(remove)) { return str.substring(remove.length()); } return str; } /** *

Removes a substring only if it is at the end of a source string, * otherwise returns the source string.

* *

A {@code null} source string will return {@code null}. * An empty ("") source string will return the empty string. * A {@code null} search string will return the source string.

* *
     * Strings.removeEnd(null, *)      = null
     * Strings.removeEnd("", *)        = ""
     * Strings.removeEnd(*, null)      = *
     * Strings.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
     * Strings.removeEnd("www.domain.com", ".com")   = "www.domain"
     * Strings.removeEnd("www.domain.com", "domain") = "www.domain.com"
     * Strings.removeEnd("abc", "")    = "abc"
     * 
* * @param str the source String to search, may be null * @param remove the String to search for and remove, may be null * @return the substring with the string removed if found, * {@code null} if null String input * @since 2.1 */ public static String removeEnd(final String str, final String remove) { if (isEmpty(str) || isEmpty(remove)) { return str; } if (str.endsWith(remove)) { return str.substring(0, str.length() - remove.length()); } return str; } /** *

Right pad a String with a specified String.

* *

The String is padded to the size of {@code size}.

* *
     * Strings.rightPad(null, *, *)      = null
     * Strings.rightPad("", 3, "z")      = "zzz"
     * Strings.rightPad("bat", 3, "yz")  = "bat"
     * Strings.rightPad("bat", 5, "yz")  = "batyz"
     * Strings.rightPad("bat", 8, "yz")  = "batyzyzy"
     * Strings.rightPad("bat", 1, "yz")  = "bat"
     * Strings.rightPad("bat", -1, "yz") = "bat"
     * Strings.rightPad("bat", 5, null)  = "bat  "
     * Strings.rightPad("bat", 5, "")    = "bat  "
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padStr the String to pad with, null or empty treated as single space * @return right padded String or original String if no padding is necessary, {@code null} if null String input */ public static String rightPad(String str, int size, String padStr) { if (str == null) { return null; } if (isEmpty(padStr)) { padStr = SPACE; } final int padLen = padStr.length(); final int strLen = str.length(); final int pads = size - strLen; if (pads <= 0) { return str; // returns original String when possible } if (padLen == 1 && pads <= PAD_LIMIT) { return rightPad(str, size, padStr.charAt(0)); } if (pads == padLen) { return str.concat(padStr); } else if (pads < padLen) { return str.concat(padStr.substring(0, pads)); } else { final char[] padding = new char[pads]; final char[] padChars = padStr.toCharArray(); for (int i = 0; i < pads; i++) { padding[i] = padChars[i % padLen]; } return str.concat(new String(padding)); } } /** *

Right pad a String with a specified character.

* *

The String is padded to the size of {@code size}.

* *
     * Strings.rightPad(null, *, *)     = null
     * Strings.rightPad("", 3, 'z')     = "zzz"
     * Strings.rightPad("bat", 3, 'z')  = "bat"
     * Strings.rightPad("bat", 5, 'z')  = "batzz"
     * Strings.rightPad("bat", 1, 'z')  = "bat"
     * Strings.rightPad("bat", -1, 'z') = "bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padChar the character to pad with * @return right padded String or original String if no padding is necessary, {@code null} if null String input */ public static String rightPad(String str, int size, char padChar) { if (str == null) { return null; } final int pads = size - str.length(); if (pads <= 0) { return str; // returns original String when possible } if (pads > PAD_LIMIT) { return rightPad(str, size, String.valueOf(padChar)); } return str.concat(repeat(padChar, pads)); } /** *

Gets the substring after the first occurrence of a separator. * The separator is not returned.

* *

A {@code null} string input will return {@code null}. * An empty ("") string input will return the empty string. * A {@code null} separator will return the empty string if the * input string is not {@code null}.

* *

If nothing is found, the empty string is returned.

* *
     * Strings.substringAfter(null, *)      = null
     * Strings.substringAfter("", *)        = ""
     * Strings.substringAfter(*, null)      = ""
     * Strings.substringAfter("abc", "a")   = "bc"
     * Strings.substringAfter("abcba", "b") = "cba"
     * Strings.substringAfter("abc", "c")   = ""
     * Strings.substringAfter("abc", "d")   = ""
     * Strings.substringAfter("abc", "")    = "abc"
     * 
* * @param str the String to get a substring from, may be null * @param separator the String to search for, may be null * @return the substring after the first occurrence of the separator, * {@code null} if null String input */ public static String substringAfter(final String str, final String separator) { if (isEmpty(str)) { return str; } if (separator == null) { return EMPTY; } final int pos = str.indexOf(separator); if (pos == -1) { return EMPTY; } return str.substring(pos + separator.length()); } /** *

Gets the substring before the first occurrence of a separator. * The separator is not returned.

* *

A {@code null} string input will return {@code null}. * An empty ("") string input will return the empty string. * A {@code null} separator will return the input string.

* *

If nothing is found, the string input is returned.

* *
     * Strings.substringBefore(null, *)      = null
     * Strings.substringBefore("", *)        = ""
     * Strings.substringBefore("abc", "a")   = ""
     * Strings.substringBefore("abcba", "b") = "a"
     * Strings.substringBefore("abc", "c")   = "ab"
     * Strings.substringBefore("abc", "d")   = "abc"
     * Strings.substringBefore("abc", "")    = ""
     * Strings.substringBefore("abc", null)  = "abc"
     * 
* * @param str the String to get a substring from, may be null * @param separator the String to search for, may be null * @return the substring before the first occurrence of the separator, {@code null} if null String input */ public static String substringBefore(String str, String separator) { if (isEmpty(str) || separator == null) { return str; } if (separator.isEmpty()) { return EMPTY; } final int pos = str.indexOf(separator); if (pos == -1) { return str; } return str.substring(0, pos); } /** *

Splits the provided text into an array, separators specified. * This is an alternative to using StringTokenizer.

* *

The separator is not included in the returned String array. * Adjacent separators are treated as one separator. * For more control over the split use the StrTokenizer class.

* *

A {@code null} input String returns {@code null}. * A {@code null} separatorChars splits on whitespace.

* *
     * Strings.split(null, *)         = null
     * Strings.split("", *)           = []
     * Strings.split("abc def", null) = ["abc", "def"]
     * Strings.split("abc def", " ")  = ["abc", "def"]
     * Strings.split("abc  def", " ") = ["abc", "def"]
     * Strings.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
     * 
* * @param str the String to parse, may be null * @param separatorChars the characters used as the delimiters, * {@code null} splits on whitespace * @return an array of parsed Strings, {@code null} if null String input */ public static String[] split(final String str, final String separatorChars) { return splitWorker(str, separatorChars, -1, false); } /** * Performs the logic for the {@code split} and * {@code splitPreserveAllTokens} methods that return a maximum array * length. * * @param str the String to parse, may be {@code null} * @param separatorChars the separate character * @param max the maximum number of elements to include in the * array. A zero or negative value implies no limit. * @param preserveAllTokens if {@code true}, adjacent separators are * treated as empty token separators; if {@code false}, adjacent * separators are treated as one separator. * @return an array of parsed Strings, {@code null} if null String input */ private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { // Performance tuned for 2.0 (JDK1.4) // Direct code is quicker than StringTokenizer. // Also, StringTokenizer uses isSpace() not isWhitespace() if (str == null) { return null; } final int len = str.length(); if (len == 0) { return EMPTY_STRING_ARRAY; } final List list = new ArrayList<>(); int sizePlus1 = 1; int i = 0; int start = 0; boolean match = false; boolean lastMatch = false; if (separatorChars == null) { // Null separator means use whitespace while (i < len) { if (Character.isWhitespace(str.charAt(i))) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } list.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } else if (separatorChars.length() == 1) { // Optimise 1 character case final char sep = separatorChars.charAt(0); while (i < len) { if (str.charAt(i) == sep) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } list.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } else { // standard case while (i < len) { if (separatorChars.indexOf(str.charAt(i)) >= 0) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } list.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } if (match || preserveAllTokens && lastMatch) { list.add(str.substring(start, i)); } return list.toArray(EMPTY_STRING_ARRAY); } /** *

Returns padding using the specified delimiter repeated * to a given length.

* *
     * Strings.repeat('e', 0)  = ""
     * Strings.repeat('e', 3)  = "eee"
     * Strings.repeat('e', -2) = ""
     * 
* * @param ch character to repeat * @param repeat number of times to repeat char, negative treated as zero * @return String with repeated character */ public static String repeat(char ch, int repeat) { if (repeat <= 0) { return EMPTY; } final char[] buf = new char[repeat]; Arrays.fill(buf, ch); return new String(buf); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy