com.aiblockchain.api.StringUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.aiblockchain.api.StringUtils.java

Source

package com.aiblockchain.api;

/*
 * StringUtils.java
 *
 * Created on October 4, 2006, 2:36 PM
 *
 * Description:
 *
 * Copyright (C) 2006 Stephen L. Reed.
 */
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.apache.log4j.Logger;

/**
 *
 * @author reed
 */
public final class StringUtils {

    // the logger
    private static final Logger LOGGER = Logger.getLogger(StringUtils.class);
    // the hex digits
    private static final String HEX_DIGITS = "0123456789abcdef";

    /**
     * Creates a new instance of StringUtils.
     */
    private StringUtils() {
    }

    /**
     * Returns a string containing the current thread name and the logger class, which is useful when the logger is conflicted or
     * otherwise not working right.
     *
     * @param logger the caller's logger
     * @return a string containing the current thread name and the logger class
     */
    public static String log(final Logger logger) {
        final String loggerClassName = logger.getName();
        int index = loggerClassName.lastIndexOf('.');
        final String loggerSimpleClassName;
        if (index < (loggerClassName.length() - 1)) {
            loggerSimpleClassName = loggerClassName.substring(index + 1);
        } else {
            loggerSimpleClassName = loggerClassName;
        }
        return new StringBuilder().append(Thread.currentThread().getName()).append(" [")
                .append(loggerSimpleClassName).append("] ").toString();
    }

    /**
     * Returns a string having each item, of the given collection, represented as a string on a separate line.
     *
     * @param items the given collection
     * @return the string representation of the given items, one per line
     */
    public static String toOneItemStringPerLine(final Collection<?> items) {
        //Preconditions
        assert items != null : "items must not be null";

        final StringBuilder stringBuilder = new StringBuilder();
        items.stream().forEach(item -> {
            stringBuilder.append(item);
            stringBuilder.append('\n');
        });
        return stringBuilder.toString();
    }

    /**
     * Returns a sorted list of the strings corresponding to the given collection of objects.
     *
     * @param objects the given collection of objects
     *
     * @return a sorted list of the strings
     */
    public static List<String> toSortedStrings(final Collection<? extends Object> objects) {
        //Preconditions
        assert objects != null : "objects must not be null";

        final List<String> strings = new ArrayList<>();
        for (final Object obj : objects) {
            strings.add(obj.toString());
        }
        Collections.sort(strings);
        return strings;
    }

    /**
     * Returns a string representation of the given float array.
     *
     * @param floatArray the given float array
     *
     * @return a string representation of the given float array
     */
    public static String floatArrayToString(final float[] floatArray) {
        final StringBuilder stringBuilder = new StringBuilder();
        boolean isFirst = true;
        stringBuilder.append('[');
        for (int i = 0; i < floatArray.length; i++) {
            if (isFirst) {
                isFirst = false;
            } else {
                stringBuilder.append(", ");
            }
            stringBuilder.append(floatArray[i]);
        }
        stringBuilder.append(']');

        return stringBuilder.toString();
    }

    /**
     * Returns a bit-string representation of the given boolean array.
     *
     * @param booleanArray the given boolean array
     *
     * @return a bit-string representation of the given boolean array
     */
    public static String booleanArrayToBitString(final boolean[] booleanArray) {
        final StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < booleanArray.length; i++) {
            if (booleanArray[i]) {
                stringBuilder.append('1');
            } else {
                stringBuilder.append('0');
            }
        }
        return stringBuilder.toString();
    }

    /**
     * Returns whether the given string is a valid Java class name.
     *
     * @param string the given string
     *
     * @return whether the given string is a valid Java class name
     */
    public static boolean isJavaClassName(final String string) {
        if (string == null || string.isEmpty() || !Character.isJavaIdentifierStart(string.charAt(0))
                || string.contains("..")) {
            return false;
        }
        for (int i = 1; i < string.length(); i++) {
            final char ch = string.charAt(i);
            if (!Character.isJavaIdentifierPart(ch) && ch != '.') {
                return false;
            }
        }
        final String[] lastNameParts = string.split("\\.");
        final String lastNamePart = lastNameParts[lastNameParts.length - 1];
        return Character.isUpperCase(lastNamePart.charAt(0));
    }

    /**
     * Returns whether the given string is a non-empty string.
     *
     * @param string the given string
     *
     * @return whether the given string is a non-empty string
     */
    public static boolean isNonEmptyString(final String string) {
        return string != null && !string.isEmpty();
    }

    /**
     * Splits the given string on spaces, which is faster than String.split(...) for this special case.
     *
     * @param string the given string
     *
     * @return the words that compose the string
     */
    public static List<String> splitOnSpace(final String string) {
        final List<String> words = new ArrayList<>();
        final int string_len = string.length();
        int index = 0;
        for (int i = 0; i < string_len; i++) {
            final char ch = string.charAt(i);
            if (ch == ' ') {
                if (i > index) {
                    words.add(string.substring(index, i));
                }
                index = i + 1;
            }
        }
        if (index < string_len) {
            words.add(string.substring(index));
        }
        return words;
    }

    /**
     * Reverses a string which consists of comma-separated items. "a, b, c" --> "c, b, a"
     *
     * @param string the given string
     *
     * @return the string with the comma-separated items reversed
     */
    public static String reverseCommaDelimitedString(final String string) {
        final List<String> items = new ArrayList<>();
        final int string_len = string.length();
        int index = 0;
        for (int i = 0; i < string_len; i++) {
            final char ch = string.charAt(i);
            if (ch == ',') {
                if (i > index) {
                    items.add(string.substring(index, i).trim());
                }
                index = i + 1;
            }
        }
        if (index < string_len) {
            items.add(string.substring(index).trim());
        }

        final StringBuilder stringBuilder = new StringBuilder();
        boolean isFirst = true;
        for (int i = items.size() - 1; i >= 0; i--) {
            if (isFirst) {
                isFirst = false;
            } else {
                stringBuilder.append(", ");
            }
            stringBuilder.append(items.get(i));
        }
        return stringBuilder.toString();
    }

    /**
     * Splits the given string on spaces and certain embedded HTML tags.
     *
     * @param string the given string
     *
     * @return the words and HTML tags that compose the string
     */
    public static List<String> splitHTMLTags(final String string) {
        if (!string.contains("<")) {
            return splitOnSpace(string);
        }
        String tempString = string;
        tempString = replace(tempString, "<br>", " <br> ");
        tempString = replace(tempString, "<ol>", " <ol> ");
        tempString = replace(tempString, "</ol>", " </ol> ");
        tempString = replace(tempString, "<ul>", " <ul> ");
        tempString = replace(tempString, "</ul>", " </ul> ");
        tempString = replace(tempString, "<li>", " <li> ");
        tempString = replace(tempString, "</li>", " </li> ");
        tempString = replace(tempString, "<strong>", " <strong> ");
        tempString = replace(tempString, "</strong>", " </strong> ");
        return splitOnSpace(tempString.trim());
    }

    /**
     * Logs the character differences between two given equal length strings.
     *
     * @param string1 the first given string
     * @param string2 the second given string
     */
    public static void logStringCharacterDifferences(final String string1, final String string2) {
        //Preconditions
        assert string1 != null : "string1 must not be null";
        assert string2 != null : "string1 must not be null";
        assert !string1.isEmpty() : "string1 must not be empty";
        assert string1.length() == string2.length() : "string1 " + string1.length() + " and string2 "
                + string2.length() + " must have the same length";

        LOGGER.info("comparing '" + string1 + "' and '" + string2 + "'...");
        for (int i = 0; i < string1.length(); i++) {
            final char ch1 = string1.charAt(i);
            final char ch2 = string2.charAt(i);
            final String message;
            if (ch1 == ch2) {
                message = "";
            } else {
                message = " not equal";
            }
            LOGGER.info("  '" + ch1 + "' - '" + ch2 + "'" + message);
        }
    }

    /**
     * Escapes embedded single quote and backslash characters in the given string.
     *
     * @param string the given string
     *
     * @return the given string with embedded single quote characters preceded by a backslash character, and with embedded backslash
     * characters preceded by another (escaping) backslash character
     */
    public static String escapeSingleQuotes(final String string) {
        if (string == null) {
            return null;
        }
        final String result = string.replaceAll("\\\\", "\\\\\\\\");
        return result.replaceAll("'", "\\\\'");
    }

    /**
     * Gets the given throwable stack trace as a string.
     *
     * @param throwable the throwable
     *
     * @return the given throwable stack trace as a string
     */
    public static String getStackTraceAsString(final Throwable throwable) {
        //Preconditions
        assert throwable != null : "ex must not be null";

        final StringWriter stringWriter = new StringWriter();
        throwable.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();
    }

    /**
     * Removes any enclosing double quotes from the given string.
     *
     * @param string the given string
     *
     * @return the given string after removing any enclosing double quotes
     */
    public static String removeEnclosingDoubleQuotes(final String string) {
        //Preconditions
        assert string != null : "string must not be null";

        String resultString = string;
        if (resultString.startsWith("\"")) {
            resultString = resultString.substring(1);
        }
        if (resultString.endsWith("\"")) {
            resultString = resultString.substring(0, resultString.length() - 1);
        }
        return resultString;
    }

    /**
     * Appends the given number of spaces to the given string builder.
     *
     * @param stringBuilder the given string builder
     * @param indent the given number of spaces
     */
    public static void indentSpaces(final StringBuilder stringBuilder, final int indent) {
        //Preconditions
        assert stringBuilder != null : "stringBuilder must not be null";
        assert indent >= 0 : "indent must not be negative";

        for (int i = 0; i < indent; i++) {
            stringBuilder.append(' ');
        }
    }

    /**
     * Appends the given number of spaces to the given buffered writer.
     *
     * @param bufferedWriter the given buffered writer
     * @param indent the given number of spaces
     */
    public static void indentSpaces(final BufferedWriter bufferedWriter, final int indent) {
        //Preconditions
        assert bufferedWriter != null : "bufferedWriter must not be null";
        assert indent >= 0 : "indent must not be negative";

        try {
            for (int i = 0; i < indent; i++) {
                bufferedWriter.write(' ');
            }
        } catch (IOException ex) {
        }
    }

    /**
     * Returns the contents of the given input stream as a string.
     *
     * @param inputStream the given input stream
     *
     * @return the contents of the given input stream as a string
     */
    public static String convertInputStreamToString(final InputStream inputStream) {
        final StringBuilder stringBuilder = new StringBuilder();
        final byte[] buffer = new byte[4096];
        try {
            while (true) {
                final int nbrChars = inputStream.read(buffer);
                if (nbrChars == -1) {
                    break;
                }
                stringBuilder.append(new String(buffer, 0, nbrChars, Charset.forName("UTF-8")));
            }
        } catch (IOException ex) {
        }
        return stringBuilder.toString();
    }

    /**
     * Returns a string of length len made up of blanks.
     *
     * @param length the length of the output String.
     *
     * @return the string of blanks.
     */
    public static String makeBlankString(final int length) {
        //Preconditions
        assert length >= 0 : "length must not be negative";

        final char[] buffer = new char[length];
        for (int i = 0; i != buffer.length; i++) {
            buffer[i] = ' ';
        }
        return new String(buffer);
    }

    /**
     * Returns given byte array as a hex string.
     *
     * @param buffer the buffer containing the bytes to be converted to hex.
     * @param length the number of bytes to be converted
     *
     * @return a hex representation of the bytes.
     */
    public static String toHex(final byte[] buffer, final int length) {
        final StringBuffer stringBuffer = new StringBuffer();

        for (int i = 0; i != length; i++) {
            final int byteValue = buffer[i] & 0xff;
            stringBuffer.append(HEX_DIGITS.charAt(byteValue >> 4));
            stringBuffer.append(HEX_DIGITS.charAt(byteValue & 0xf));
        }

        return stringBuffer.toString();
    }

    /**
     * Returns the given byte array as a hex string.
     *
     * @param buffer the bytes to be converted.
     *
     * @return a hex representation of data.
     */
    public static String toHex(final byte[] buffer) {
        return toHex(buffer, buffer.length);
    }

    /**
     * Returns the package name from the fully qualified class name.
     *
     * @param className the fully qualified class name
     *
     * @return the package name
     */
    public static String packageFromClassName(final String className) {
        //Preconditions
        assert className != null : "className must not be null";
        assert !className.isEmpty() : "className must not be empty";

        final int index = className.lastIndexOf('.');
        assert index > -1 : "cannot find package in import " + className;
        return className.substring(0, index);
    }

    /**
     * Returns the simple class name from the fully qualified class name.
     *
     * @param className the fully qualified class name
     *
     * @return the package name
     */
    public static String simpleClassName(final String className) {
        //Preconditions
        assert className != null : "className must not be null";
        assert !className.isEmpty() : "className must not be empty";

        final int index = className.lastIndexOf('.');
        assert index > -1 : "cannot find package in import " + className;
        return className.substring(index + 1);
    }

    /**
     * Gets a lower case predicate or variable name derived from the given simple class name.
     *
     * @param simpleClassName the given simple class name
     *
     * @return a lower case predicate or variable name derived from the given simple class name
     */
    public static String getLowerCasePredicateName(final String simpleClassName) {
        //Preconditions
        assert simpleClassName != null : "simpleClassName must not be null";
        assert !simpleClassName.isEmpty() : "simpleClassName must not be empty";

        // predicates begin with a lower case letter, but class names are capitalized and may also begin with a accronym
        if (simpleClassName.length() == 1) {
            // trivial case
            return simpleClassName.toLowerCase(Locale.ENGLISH);
        } else {
            final StringBuilder stringBuilder = new StringBuilder();

            int index = 0;
            final int simpleClassName_len = simpleClassName.length();
            while (true) {
                if (index >= simpleClassName_len) {
                    // reached the end with all upper case characters
                    break;
                }
                char ch = simpleClassName.charAt(index);
                stringBuilder.append(Character.toLowerCase(ch));

                if (index < simpleClassName_len - 2 && Character.isUpperCase(simpleClassName.charAt(index + 1))
                        && Character.isLowerCase(simpleClassName.charAt(index + 2))) {
                    break;
                } else if (index < simpleClassName_len - 1
                        && Character.isLowerCase(simpleClassName.charAt(index + 1))) {
                    break;
                }
                index++;
            }

            // copy any remaining characters unchanged
            for (int i = index + 1; i < simpleClassName_len; i++) {
                stringBuilder.append(simpleClassName.charAt(i));
            }
            return stringBuilder.toString();
        }
    }

    /**
     * Ensures that the given string builder has one newline characters at the end of its buffer.
     *
     * @param stringBuilder the given string builder
     */
    public static void ensureOneNewLine(final StringBuilder stringBuilder) {
        //Preconditions
        assert stringBuilder != null : "stringBuilder must not be null";

        final int length = stringBuilder.length();
        if (length == 0) {
            stringBuilder.append('\n');
            return;
        }
        final char ch1 = stringBuilder.charAt(length - 1);
        if (ch1 == '\n') {
            return;
        } else {
            stringBuilder.append('\n');
            return;
        }
    }

    /**
     * Ensures that the given string builder has two newline characters at the end of its buffer.
     *
     * @param stringBuilder the given string builder
     */
    public static void ensureTwoNewLines(final StringBuilder stringBuilder) {
        //Preconditions
        assert stringBuilder != null : "stringBuilder must not be null";

        final int length = stringBuilder.length();
        if (length == 0) {
            stringBuilder.append('\n');
            stringBuilder.append('\n');
            return;
        }
        final char ch1 = stringBuilder.charAt(length - 1);
        if (length == 1) {
            stringBuilder.append('\n');
            if (ch1 == '\n') {
                return;
            } else {
                stringBuilder.append('\n');
                return;
            }
        }
        final char ch2 = stringBuilder.charAt(length - 2);
        if (ch1 == '\n') {
            if (ch2 == '\n') {
                return;
            } else {
                stringBuilder.append('\n');
                return;
            }
        } else {
            stringBuilder.append('\n');
            stringBuilder.append('\n');
            return;
        }
    }

    /**
     * Returns the single string formed by concatenating the given strings, separating them by a space.
     *
     * @param strings the given strings
     *
     * @return the single string formed by concatenating the given strings, separating them by a space
     */
    public static String toSingleString(final List<String> strings) {
        //Preconditions
        assert strings != null : "strings must not be null";

        final StringBuilder stringBuilder = new StringBuilder();
        boolean isFirst = true;
        for (final String string : strings) {
            if (isFirst) {
                isFirst = false;
            } else {
                stringBuilder.append(' ');
            }
            stringBuilder.append(string);
        }
        return stringBuilder.toString();
    }

    /**
     * Returns the given string padded with spaces if required to have the given length.
     *
     * @param string the given string
     * @param length the given length
     *
     * @return the given string padded with spaces if required to have the given length
     */
    public static String padWithTrailingSpaces(final String string, final int length) {
        //Preconditions
        assert string != null : "string must not be null";

        final int string_len = string.length();
        if (string_len >= length) {
            return string;
        }
        final StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(string);
        final int nbrSpacesToPad = length - string_len;
        for (int i = 0; i < nbrSpacesToPad; i++) {
            stringBuilder.append(' ');
        }
        return stringBuilder.toString();
    }

    /**
     * Returns the given string after removing any numeric suffix.
     *
     * @param string the given string
     *
     * @return the given string after removing any numeric suffix
     */
    public static String stripNumericSuffix(final String string) {
        //Preconditions
        assert string != null : "string must not be null";

        if (string.isEmpty()) {
            return string;
        }
        int index = string.length() - 1;
        while (index >= 0) {
            if (Character.isDigit(string.charAt(index))) {
                index--;
            } else {
                break;
            }
        }
        return string.substring(0, index + 1);
    }

    /**
     * Returns whether two lists of strings are consistent with respect to order, while allowing missing items in the second list, and
     * allowing optional capitalization of the first word in the first list.
     *
     * @param strings1 the first list of strings
     * @param strings2 the second list of strings
     *
     * @return
     */
    public static boolean isOrderConsistent(final List<String> strings1, final List<String> strings2) {
        //Preconditions
        assert strings1 != null : "strings1 must not be null";
        assert strings2 != null : "strings2 must not be null";

        if (strings1.size() < strings2.size()) {
            return false;
        } else if (strings1.isEmpty()) {
            return true;
        }
        int index1 = 0;
        int index2 = 0;
        while (true) {
            String string1 = strings1.get(index1);
            if (index2 >= strings2.size()) {
                // reached the end of the second list before finding the expected match
                return false;
            }
            final String string2 = strings2.get(index2);
            if (string1.equals(string2) || (index1 == 0 && StringUtils.uncapitalize(string1).equals(string2))) {
                index1++;
                index2++;
                if (index1 >= strings1.size()) {
                    // reached the end of the first list, return whether the end of the second list has also been reached
                    return index2 >= strings2.size();
                } else {
                    continue;
                }
            }
            while (true) {
                index1++;
                if (index1 >= strings1.size()) {
                    // reached the end of the first before finding the expected match
                    return false;
                }
                string1 = strings1.get(index1);
                if (string1.equals(string2)) {
                    // found expected match after possibly skipping items in the second list
                    break;
                }
            }
        }
    }

    // Adapted from the Spring Framework org.springframework.util.SpringUtils having the Apache license.
    //---------------------------------------------------------------------
    // General convenience methods for working with Strings
    //---------------------------------------------------------------------
    /**
     * Capitalizes a <code>String</code>, changing the first letter to upper case as per {@link Character#toUpperCase(char)}. No other letters
     * are changed.
     *
     * @param string the String to capitalize, may be <code>null</code>
     *
     * @return the capitalized String, <code>null</code> if null
     */
    public static String capitalize(final String string) {
        return changeFirstCharacterCase(string, true);
    }

    /**
     * Uncapitalizes a <code>String</code>, changing the first letter to lower case as per {@link Character#toLowerCase(char)}. No other
     * letters are changed.
     *
     * @param string the String to uncapitalize, may be <code>null</code>
     *
     * @return the uncapitalized String, <code>null</code> if null
     */
    public static String uncapitalize(final String string) {
        return changeFirstCharacterCase(string, false);
    }

    /**
     * Changes case of the first character of the string.
     *
     * @param string the given string
     * @param isCapitalized whether to capitalize the first character
     *
     * @return the transformed string
     */
    private static String changeFirstCharacterCase(final String string, final boolean isCapitalized) {
        if (string == null || string.length() == 0) {
            return string;
        }
        final StringBuilder stringBuilder = new StringBuilder(string.length());
        if (isCapitalized) {
            stringBuilder.append(Character.toUpperCase(string.charAt(0)));
        } else {
            stringBuilder.append(Character.toLowerCase(string.charAt(0)));
        }
        stringBuilder.append(string.substring(1));
        return stringBuilder.toString();
    }

    /**
     * Returns whether the given CharSequence is neither <code>null</code> nor length 0. Note: Will return <code>true</code> for a
     * CharSequence that purely consists of whitespace.
     *
     * @param str the CharSequence to check (may be <code>null</code>)
     *
     * @return <code>true</code> if the CharSequence is not null and has length
     * @see #hasText(String)
     */
    public static boolean hasLength(final CharSequence str) {
        return (str != null && str.length() > 0);
    }

    /**
     * Returns whether the given String is neither <code>null</code> nor length 0. Note: Will return <code>true</code> for a String that
     * purely consists of whitespace.
     *
     * @param str the String to check (may be <code>null</code>)
     *
     * @return <code>true</code> if the String is not null and has length
     * @see #hasLength(CharSequence)
     */
    public static boolean hasLength(final String str) {
        return hasLength((CharSequence) str);
    }

    /**
     * Replaces all occurrences of a substring within a string with another string.
     *
     * @param inString String to examine
     * @param oldPattern String to replace
     * @param newPattern String to insert
     *
     * @return a String with the replacements
     */
    public static String replace(final String inString, final String oldPattern, final String newPattern) {
        //Preconditions
        assert inString != null : "inString must not be null";
        assert oldPattern != null : "oldPattern must not be null";
        assert newPattern != null : "newPattern must not be null";

        if (!hasLength(inString) || !hasLength(oldPattern)) {
            return inString;
        }
        final StringBuilder stringBuilder = new StringBuilder();
        int pos = 0; // our position in the old string
        int index = inString.indexOf(oldPattern);
        // the index of an occurrence we've found, or -1
        final int patLen = oldPattern.length();
        while (index >= 0) {
            stringBuilder.append(inString.substring(pos, index));
            stringBuilder.append(newPattern);
            pos = index + patLen;
            index = inString.indexOf(oldPattern, pos);
        }
        stringBuilder.append(inString.substring(pos));
        // remember to append any characters to the right of a match
        return stringBuilder.toString();
    }

    /**
     * Counts the occurrences of the substring in the given string.
     *
     * @param string the given string
     * @param substring the given substring
     *
     * @return the number of occurrences
     */
    public static int countOccurrencesOf(final String string, final String substring) {
        if (string == null || substring == null || string.length() == 0 || substring.length() == 0) {
            return 0;
        }
        int count = 0;
        int pos = 0;
        int idx;
        while ((idx = string.indexOf(substring, pos)) != -1) {
            ++count;
            pos = idx + substring.length();
        }
        return count;
    }

    /**
     * Strips punctuation and digits from the given string.
     *
     * @param string the given string
     *
     * @return a string consisting of the given string with punctuation and digits removed
     */
    public static String stripPunctuationAndDigits(final String string) {
        //Preconditions
        assert string != null : "string must not be null";

        final StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < string.length(); i++) {
            final char char1 = string.charAt(i);
            if (char1 == 45) {
                stringBuilder.append(' '); // replace dash with space
            } else if ((char1 >= 9 && char1 <= 13) || // whitespace
                    char1 == 32 || // space
                    (char1 >= 65 && string.charAt(i) <= 90) || // uppercase letters
                    (char1 >= 97 && char1 <= 122)) { // lowercase letters
                stringBuilder.append(string.charAt(i));
            }
        }
        return stringBuilder.toString();
    }
}