com.qtplaf.library.util.StringUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.qtplaf.library.util.StringUtils.java

Source

/*
 * Copyright (C) 2015 Miquel Sas
 * 
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package com.qtplaf.library.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.StringTokenizer;

import javax.swing.KeyStroke;

import com.qtplaf.library.app.Session;

/**
 * String utilities extended from Apache Commons Lang.
 *
 * @author Miquel Sas
 */
public class StringUtils extends org.apache.commons.lang3.StringUtils {

    /**
     * Sample list of digits to generate random digits.
     */
    public static final String DIGITS = "0123456789";
    /**
     * Sample list of letters to generate random letters.
     */
    public static final String LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    /**
     * Returns a random char within the source string.
     * 
     * @param source The source string.
     * @return The random char.
     */
    public static char getRandomChar(String source) {
        int index = Random.nextInt(source.length());
        return source.charAt(index);
    }

    /**
     * Returns the stack trace as a string.
     * 
     * @param exc The exception.
     * @return The stack trace as a string.
     */
    public static String getStackTrace(Exception exc) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        exc.printStackTrace(pw);
        return sw.toString();
    }

    /**
     * Separates with a blank the different tokens that can compose a normal class or method name, like for instance
     * doSomething into Do something.
     *
     * @param str The string to separate.
     * @return The separated string.
     */
    public static String separeTokens(String str) {
        StringBuilder b = new StringBuilder();
        if (str != null) {
            for (int i = 0; i < str.length(); i++) {
                if (i == 0) {
                    b.append(Character.toUpperCase(str.charAt(i)));
                } else {
                    if (Character.isLowerCase(str.charAt(i - 1)) && Character.isUpperCase(str.charAt(i))) {
                        b.append(' ');
                        if ((i < str.length() - 1) && Character.isUpperCase(str.charAt(i + 1))) {
                            b.append(str.charAt(i));
                        } else {
                            b.append(Character.toLowerCase(str.charAt(i)));
                        }
                    } else {
                        b.append(str.charAt(i));
                    }
                }
            }
        }
        return b.toString();
    }

    /**
     * Parse a comma delimited "XX","XX","XX" string, and return an array with its elements.
     *
     * @param strToParse The String to parse.
     * @return An array of strings that are the parts of the comma delimited string to parse.
     */
    public static String[] parseCommaDelimitedString(String strToParse) {
        if (strToParse.length() == 0) {
            return new String[0];
        }
        int start = 0;
        while (strToParse.charAt(start) != '\"') {
            start++;
        }
        int end = strToParse.length() - 1;
        while (strToParse.charAt(end) != '\"') {
            end--;
        }
        strToParse = strToParse.substring(++start, end);
        ArrayList<String> list = new ArrayList<>();
        start = 0;
        while (true) {
            end = strToParse.indexOf("\",\"", start);
            if (end == -1) {
                list.add(strToParse.substring(start));
                break;
            }
            list.add(strToParse.substring(start, end));
            start = end + 3;
        }
        return list.toArray(new String[list.size()]);
    }

    /**
     * Utility to parse command line arguments in the form of arg=value. Returns a map with the arguments as pairs of
     * keys/values.
     *
     * @param arguments The array of command line arguments.
     * @return A map with pairs of argument/value.
     */
    public static HashMap<String, String> parseArgs(String[] arguments) {
        HashMap<String, String> map = new HashMap<>();
        if (arguments != null) {
            for (String argument : arguments) {
                String[] parts = split(argument, "=");
                if (parts.length == 0) {
                    continue;
                }
                String arg = parts[0];
                String val = arg;
                if (parts.length > 1) {
                    val = parts[1];
                }
                map.put(arg, val);
            }
        }
        return map;
    }

    /**
     * Parses a string of the form "en-US,es-ES,fr,FR" or "en_US,es_ES,fr_FR" into an array of locales.
     *
     * @param str The argument string.
     * @return The parsed array of locales.
     */
    public static Locale[] parseLocales(String str) {
        ArrayList<Locale> locales = new ArrayList<>();
        String[] strLoc = split(str, ",");
        for (String strLoc1 : strLoc) {
            Locale locale = parseLocale(strLoc1);
            if (locale == null) {
                continue;
            }
            locales.add(locale);
        }
        return locales.toArray(new Locale[locales.size()]);
    }

    /**
     * Parse a locale in the form "en-US" or "en_US"
     *
     * @param str The locale string
     * @return The locale or null.
     */
    public static Locale parseLocale(String str) {
        String[] parts = split(str.trim(), "_-");
        if (parts.length == 1) {
            return new Locale(parts[0].trim());
        }
        if (parts.length >= 2) {
            return new Locale(parts[0].trim(), parts[1].trim());
        }
        return null;
    }

    /**
     * Parse a comma separated list of strings "S1, S2, S3".
     *
     * @param string The string to be tokenized.
     * @return the array of tokens.
     */
    public static String[] parseCommaSeparatedStrings(String string) {
        StringTokenizer tokenizer = new StringTokenizer(string, ",");
        ArrayList<String> list = new ArrayList<>();
        while (tokenizer.hasMoreTokens()) {
            list.add(tokenizer.nextToken().trim());
        }
        return list.toArray(new String[list.size()]);
    }

    /**
     * Parse a string
     * 
     * @param string The string to parse.
     * @param separator The separator.
     * @return the array of tokens
     */
    public static String[] parse(String string, String separator) {
        StringTokenizer tokenizer = new StringTokenizer(string, separator);
        ArrayList<String> list = new ArrayList<>();
        while (tokenizer.hasMoreTokens()) {
            list.add(tokenizer.nextToken().trim());
        }
        return list.toArray(new String[list.size()]);
    }

    /**
     * Converts a String to a new String using a selected charset.
     *
     * @param in The input String
     * @param charset The charset to convert.
     * @return A String.
     * @throws UnsupportedEncodingException If the char set does not exist.
     */
    public static String encodeString(String in, String charset) throws UnsupportedEncodingException {
        return new String(in.getBytes(charset));
    }

    /**
     * This method unescapes a message. It is useful to decode the request arguments in a HTTP Query String or a HTTP
     * form URL encoded request.
     *
     * @param msg The String to be unescaped.
     * @param charsetName The charset to be used.
     * @return the unescaped String
     * @throws UnsupportedEncodingException If the char set does not exist.
     */
    public static String toUnescaped(String msg, String charsetName) throws UnsupportedEncodingException {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < msg.length(); i++) {
            char c = msg.charAt(i);
            if (c == '%') {
                String hex = msg.substring(i + 1, i + 3);
                list.add(Integer.valueOf(hex, 16));
                i += 2;
            } else {
                list.add(Integer.valueOf((byte) c));
            }
        }
        byte[] buff = new byte[list.size()];
        for (int i = 0; i < list.size(); i++) {
            buff[i] = list.get(i).byteValue();
        }
        return new String(buff, charsetName);
    }

    /**
     * This method unescapes a message. It is useful to decode the request arguments in a HTTP Query String or a HTTP
     * form URL encoded request.
     *
     * @param bytes The byte array to be unescaped.
     * @param charsetName The charset to be used.
     * @return the unescaped String
     * @throws UnsupportedEncodingException If the char set does not exist.
     */
    public static String toUnescaped(byte[] bytes, String charsetName) throws UnsupportedEncodingException {
        return toUnescaped(new String(bytes), charsetName);
    }

    /**
     * This method escapes a message. It is useful to encode the request arguments in a HTTP GET request method.
     *
     * @param msg The String to be escaped.
     * @param charsetName The charset to be used.
     * @return the escaped String
     * @throws UnsupportedEncodingException In msg.getBytes(charsetName)
     */
    public static String toEscaped(String msg, String charsetName) throws UnsupportedEncodingException {
        byte[] buff = msg.getBytes(charsetName);
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < buff.length; i++) {
            int c = buff[i];
            if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c < 'z'))) {
                b.append((char) c);
            } else {
                b.append('%');
                b.append(Integer.toHexString(c & 0xff).toUpperCase());
            }
        }
        return b.toString();
    }

    /**
     * Returns the first string not null, or an empty string.
     * 
     * @param strings The list of strings.
     * @return The first string not null, or an empty string.
     */
    public static String getFirstNotNull(String... strings) {
        StringBuilder b = new StringBuilder();
        for (String s : strings) {
            if (s != null) {
                b.append(s);
                break;
            }
        }
        return b.toString();
    }

    /**
     * Returns Levenshtein distance between two strings, useful to mesure the similarity of those strings.
     * 
     * @param s Start string.
     * @param t Target string.
     * @return An integer that mesures the Levenshtein distance.
     */
    public static int getLevenshteinDistance(String s, String t) {
        if (s == null || t == null) {
            throw new NullPointerException();
        }

        /*
         * The difference between this implementation and the previous is that, rather than creating and retaining a
         * matrix of size s.length()+1 by t.length()+1, we maintain two single-dimensional arrays of length
         * s.length()+1. The first, d, is the 'current working' distance array that maintains the newest distance cost
         * counts as we iterate through the characters of String s. Each time we increment the index of String t we are
         * comparing, d is copied to p, the second int[]. Doing so allows us to retain the previous cost counts as
         * required by the algorithm (taking the minimum of the cost count to the left, up one, and diagonally up and to
         * the left of the current cost count being calculated). (Note that the arrays aren't really copied anymore,
         * just switched...this is clearly much better than cloning an array or doing a System.arraycopy() each time
         * through the outer loop.)
         * 
         * Effectively, the difference between the two implementations is this one does not cause an out of memory
         * condition when calculating the LD over two very large strings.
         */
        int n = s.length(); // length of s
        int m = t.length(); // length of t

        if (n == 0) {
            return m;
        } else if (m == 0) {
            return n;
        }

        int p[] = new int[n + 1]; // 'previous' cost array, horizontally
        int d[] = new int[n + 1]; // cost array, horizontally
        int _d[]; // placeholder to assist in swapping p and d

        // indexes into strings s and t
        int i; // iterates through s
        int j; // iterates through t

        char t_j; // jth character of t

        int cost; // cost

        for (i = 0; i <= n; i++) {
            p[i] = i;
        }

        for (j = 1; j <= m; j++) {
            t_j = t.charAt(j - 1);
            d[0] = j;

            for (i = 1; i <= n; i++) {
                cost = s.charAt(i - 1) == t_j ? 0 : 1;
                // minimum of cell to the left+1, to the top+1, diagonally left
                // and up +cost
                d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
            }

            // copy current distance counts to 'previous row' distance counts
            _d = p;
            p = d;
            d = _d;
        }

        // our last action in the above loop was to switch d and p, so p now
        // actually has the most recent cost counts
        return p[n];
    }

    /**
     * Returns a string representation of a key stroke.
     * 
     * @param keyStroke The key stroke.
     * @return The string representation.
     */
    public static String toString(KeyStroke keyStroke) {
        String[] tokens = split(keyStroke.toString(), " ");
        StringBuilder b = new StringBuilder();
        for (String token : tokens) {
            if (token.equals("typed") || token.equals("released") || token.equals("pressed")) {
                continue;
            }
            if (b.length() > 0) {
                b.append(" ");
            }
            b.append(capitalize(token.toLowerCase()));
        }
        return b.toString();
    }

    /**
     * Check if the string is contained in the list of options.
     * 
     * @param string The source string.
     * @param options The list of options.
     * @return A boolean.
     */
    public static boolean in(String string, String... options) {
        for (String option : options) {
            if (option.equals(string)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check if the string is contained in the list of options, case insensitive.
     * 
     * @param string The source string.
     * @param options The list of options.
     * @return A boolean.
     */
    public static boolean inNoCase(String string, String... options) {
        string = string.toLowerCase();
        for (String option : options) {
            if (option.toLowerCase().equals(string)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Append if not null.
     * 
     * @param b The string builder.
     * @param o The object to add.
     */
    public static void append(StringBuilder b, Object o) {
        if (o != null) {
            b.append(o);
        }
    }

    /**
     * Append separated if not null, inserting the separator if the buffer is not empty.
     * 
     * @param b The string builder.
     * @param o The object to add.
     * @param sep The separator.
     */
    public static void appendSep(StringBuilder b, Object o, String sep) {
        if (o != null) {
            if (b.length() > 0) {
                b.append(sep);
            }
            b.append(o);
        }
    }

    /**
     * Parse and capitalize.
     * 
     * @param srcStr Source string.
     * @param srcSep Source separator.
     * @param dstSep Destination separator.
     * @return The capitalized string.
     */
    public static String parseCapitalize(String srcStr, String srcSep, String dstSep) {
        StringBuilder b = new StringBuilder();
        String[] words = StringUtils.parse(srcStr, srcSep);
        for (int i = 0; i < words.length; i++) {
            if (i > 0) {
                b.append(dstSep);
            }
            b.append(StringUtils.capitalize(words[i]));
        }
        return b.toString();
    }

    /**
     * Returns the suffix given the separator.
     * 
     * @param src The source string.
     * @param sep The seprator.
     * @return The suffix.
     */
    public static String getSuffix(String src, String sep) {
        int index = src.lastIndexOf(sep);
        return src.substring(index + 1);
    }

    /**
     * Returns the time information string (seconds,minutes or hours).
     * 
     * @param session Working session.
     * @param time The time in millis.
     * @return The time info.
     */
    public static String getTimeString(Session session, double time) {
        int decimals = 1;
        double seconds = (time / 1000.0);
        if (seconds < 60) {
            StringBuilder b = new StringBuilder();
            b.append(FormatUtils.formattedFromDouble(seconds, decimals, session.getLocale()));
            b.append(" ");
            b.append(session.getString("tokenSeconds").toLowerCase());
            return b.toString();
        }
        double minutes = (time / (1000.0 * 60.0));
        if (minutes < 60) {
            StringBuilder b = new StringBuilder();
            b.append(FormatUtils.formattedFromDouble(minutes, decimals, session.getLocale()));
            b.append(" ");
            b.append(session.getString("tokenMinutes").toLowerCase());
            return b.toString();
        }
        double hours = (time / (1000.0 * 60.0 * 60.0));
        StringBuilder b = new StringBuilder();
        b.append(FormatUtils.formattedFromDouble(hours, decimals, session.getLocale()));
        b.append(" ");
        b.append(session.getString("tokenHours").toLowerCase());
        return b.toString();
    }

    /**
     * Return the string representation of the vector.
     * 
     * @param a The vector.
     * @return The string representation.
     */
    public static String toString(char[] a) {
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < a.length; i++) {
            if (i > 0) {
                b.append(", ");
            }
            b.append(a[i]);
        }
        return b.toString();
    }

    /**
     * Return the string representation of the vector.
     * 
     * @param a The vector.
     * @return The string representation.
     */
    public static String toString(double[] a) {
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < a.length; i++) {
            if (i > 0) {
                b.append(", ");
            }
            b.append(a[i]);
        }
        return b.toString();
    }

}