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

org.nuiton.util.StringUtil Maven / Gradle / Ivy

There is a newer version: 3.1
Show newest version
/*
 * #%L
 * Nuiton Utils
 * %%
 * Copyright (C) 2004 - 2011 CodeLutin, Chatellier Eric
 * %%
 * 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%
 */

package org.nuiton.util;

import org.apache.commons.lang3.SystemUtils;

import java.awt.Color;
import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * Classe contenant un ensemle de methode static utiles pour la manipulation des
 * chaine de caractere mais qui ne sont pas defini dans la classe String de
 * Java.
 *
 * Created: 21 octobre 2003
 *
 * @author Benjamin Poussin - [email protected]
 * @author Tony Chemit - [email protected]
 *
 */
public class StringUtil { // StringUtil

    public static final String[] EMPTY_STRING_ARRAY = new String[0];

    /** Constructor for the StringUtil object */
    protected StringUtil() {
    }

    /**
     * Know if a string is a valid e-mail.
     *
     * @param str a string
     * @return true if {@code str} is syntactically a valid e-mail address
     * @since 2.1
     */
    public static boolean isEmail(String str) {
        return str.matches("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+((\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)?)+@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\\-]*[a-zA-Z0-9])?$");
    }

    /**
     * Add quotes if needed to escape special csv chars (',', '\n', '\t', ',', ';', '"')
     *
     * @param value        to escape
     * @param csvSeparator separator used for csv
     * @return escaped if needed value
     */
    public static String escapeCsvValue(String value, String csvSeparator) {

        boolean valueNeedQuotes =
                value.contains("\n")
                || value.contains("\t")
                || value.contains(",")
                || value.contains(";")
                || value.contains("\"")
                || value.contains(csvSeparator);

        if (valueNeedQuotes) {
            // escape '"' char to prevent
            value = value.replaceAll("\"", "\"\"");
            value = "\"" + value + "\"";
        }
        return value;
    }

    /**
     * Contract to use in {@link StringUtil#join(Iterable, ToString, String, boolean) }
     * method. This will provide a toString method to convert an object in a
     * string.
     *
     * @param  type of object manipulated
     */
    public interface ToString {

        /**
         * Convert an object o in a string.
         *
         * @param o to convert
         * @return the string for this object o
         */
        String toString(O o);
    }

    /**
     * Used to build csv file using {@link StringUtil#join(Iterable, ToString, String, boolean) }
     * method. This will provide a toString method to convert an object in a
     * string and escape csv values if needed.
     *
     * @param  type of object manipulated
     */
    public static class ToCSV implements StringUtil.ToString {

        protected String csvSeparator;

        public ToCSV(String csvSeparator) {
            this.csvSeparator = csvSeparator;
        }

        @Override
        public String toString(O o) {
            String value = getStringValue(o);
            return escapeCsvValue(value, csvSeparator);
        }

        /**
         * Use {@link Object#toString()} method by default
         * Must be override to use other methods to get string value.
         *
         * @param o to convert
         * @return String value
         */
        public String getStringValue(O o) {
            return o.toString();
        }
    }

    /**
     * Used to concat an {@code iterable} of Object separated
     * by {@code separator} using the toString() method of each object.
     * You can specify if the string must be trimmed or not.
     *
     * @param iterable  Iterable with objects to treate
     * @param separator to used
     * @param trim      if each string must be trim
     * @return the String chain of all elements separated by separator, never
     *         return null, will return an empty String for an empty list.
     */
    public static String join(Iterable iterable, String separator,
                              boolean trim) {
        String result = join(iterable, null, separator, trim);
        return result;
    }

    /**
     * Used to concat an {@code iterable} of object {@code } separated by
     * {@code separator}. This method need a {@code ts} contract to
     * call on each object. The ToString can be null to use directly the
     * toString() method on the object. The {@code trim} boolean is used
     * to specify if each string object has to be trimmed. The null elements
     * in the {@code list} will be ignored.
     *
     * @param        type of object in the list
     * @param iterable  Iterable with objects to treate
     * @param ts        used to specify how the object is converted in String
     * @param separator to used between each object string
     * @param trim      if trim() method need to by apply on each object string
     * @return the String chain of all elements separated by separator, never
     *         return null, will return an empty String for an empty list.
     * @throws NullPointerException if iterable is {@code null}.
     */
    public static  String join(Iterable iterable, ToString ts,
                                  String separator, boolean trim) throws NullPointerException {
        if (iterable == null) {
            throw new NullPointerException("null iterable can't be used" +
                                           " to join the elements with " + separator);
        }
        // Do nothing for an empty list
        if (!iterable.iterator().hasNext()) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        for (O o : iterable) {
            // Ignore the null object in the list
            if (o == null) {
                continue;
            }
            String str;
            // Use ToString contract from argument
            if (ts != null) {
                str = ts.toString(o);
                // Or call toString() method directly on object
            } else {
                str = o.toString();
            }
            // Apply trim if needed
            if (trim) {
                str = str.trim();
            }
            builder.append(separator).append(str);
        }
        // Suppress the first separator at beginning of the chain
        String result = builder.substring(separator.length());
        return result;
    }

    /**
     * substring from begin to end of s
     *
     * example:
     * substring("tatetitotu", -4) → totu
     *
     * @param s     the string to substring
     * @param begin if begin < 0 then begin start at end of string - begin
     * @return the result of substring
     */
    public static String substring(String s, int begin) {
        String result = substring(s, begin, s.length());
        return result;
    }

    /**
     * substring from begin to end of s
     *
     * example:
     * substring("tatetitotu", -4, -2) → to
     *
     * @param s     the string to substring
     * @param begin if begin < 0 then begin start at end of string - begin
     * @param end   if end < 0 then end start at end of string - end
     * @return the result of substring
     */
    public static String substring(String s, int begin, int end) {
        if (begin < 0) {
            begin = s.length() + begin;
        }
        if (end < 0) {
            end = s.length() + end;
        }
        if (end < begin) {
            end = begin;
        }

        String result;
        result = s.substring(begin, end);
        return result;
    }

    private static final Character[] openingChars = {'(', '{', '['};

    private static final Character[] closingChars = {')', '}', ']'};

    /**
     * Split string use 'separator' as separator. If String contains "'()[]{}
     * this method count the number of open char end close char to split
     * correctly argument
     *
     * WARNING: cette method ne fonctionne pas si le contenu contient
     * des carateres utilisé pour le parsing et présent une seule fois.
     * Par exemple: "l'idenfiant" contient ' qui empeche totalement le
     * parsing de fonctionner.
     *
     * @param args      string to split
     * @param separator separator use to split string
     * @return array of string
     */
    public static String[] split(String args, String separator) {
        return split(openingChars, closingChars, args, separator);
    }


    /**
     * Use to split string array representation in array according with ',' as
     * default separator.
     *
     * WARNING: cette method ne fonctionne pas si le contenu contient
     * des carateres utilisé pour le parsing et présent une seule fois.
     * Par exemple: "l'idenfiant" contient ' qui empeche totalement le
     * parsing de fonctionner.
     *
     * @param stringList string that represent array
     * @return array with length > 0 if listAsString ≠ null or null
     */
    public static String[] split(String stringList) {
        String[] result;
        result = split(stringList, ",");
        return result;
    }

    /**
     * Split string use 'separator' as separator. If String contains "'
     * and {@code openingChar} {@code closingChars}
     *
     * this method count the number of open char end close char to split
     * correctly argument
     *
     * WARNING: cette method ne fonctionne pas si le contenu contient
     * des carateres utilisé pour le parsing et présent une seule fois.
     * Par exemple: "l'idenfiant" contient ' qui empeche totalement le
     * parsing de fonctionner.
     *
     * @param openingChars list of opening caracteres
     * @param closingChars list of closing caracteres
     * @param args         string to split
     * @param separator    separator use to split string
     * @return array of string
     */
    public static String[] split(Character[] openingChars,
                                 Character[] closingChars,
                                 String args, String separator) {
        if (args == null) {
            return EMPTY_STRING_ARRAY;
        }

        List result = new ArrayList();

        int start = 0;
        int end;
        StringBuilder op = new StringBuilder(); // stack of {([< currently open
        char last = '\0'; // contains " or ' if string is openned

        List opening = Arrays.asList(openingChars);

        List closing = Arrays.asList(closingChars);

        for (int i = 0; i < args.length(); i++) {
            char c = args.charAt(i);
            if (c == '\\') {
                // pass next char
                i++;
            } else if (last != '"' && last != '\'') {
                if (opening.contains(c)) {
                    op.append(c);
                } else if (closing.contains(c)) {
                    op.deleteCharAt(op.length() - 1);
                } else if (c == '"' || c == '\'') {
                    // open string " or '
                    last = c;
                } else if (op.length() == 0 &&
                           args.regionMatches(i, separator, 0,
                                              separator.length())) {
                    // end of one arguement
                    end = i;
                    // pass separator
                    i += separator.length() - 1;

                    String a = args.substring(start, end);
                    result.add(a);
                    // start of next argument
                    start = end + separator.length();
                }
            } else if (c == last) {
                // close string " or '
                last = '\0';
            }
        }

        if (start < args.length()) {
            String a = args.substring(start, args.length());
            result.add(a);
        }

        return result.toArray(new String[result.size()]);
    }

    public static boolean toBoolean(String s) {
        return "true".equalsIgnoreCase(s);
    }

    public static byte toByte(String s) {
        return Byte.parseByte(s);
    }

    public static double toDouble(String s) {
        return Double.parseDouble(s);
    }

    public static float toFloat(String s) {
        return Float.parseFloat(s);
    }

    public static long toLong(String s) {
        return Long.parseLong(s);
    }

    public static short toShort(String s) {
        return Short.parseShort(s);
    }

    public static int toInt(String s) {
        return Integer.parseInt(s);
    }

    public static char toChar(String s) {
        // fixme a revoir
        return s.charAt(0);
    }

    public static boolean[] toArrayBoolean(String... s) {
        boolean[] result = new boolean[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toBoolean(s[i]);
        }
        return result;
    }

    public static byte[] toArrayByte(String... s) {
        byte[] result = new byte[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toByte(s[i]);
        }
        return result;
    }

    public static double[] toArrayDouble(String... s) {
        double[] result = new double[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toDouble(s[i]);
        }
        return result;
    }

    public static float[] toArrayFloat(String... s) {
        float[] result = new float[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toFloat(s[i]);
        }
        return result;
    }

    public static long[] toArrayLong(String... s) {
        long[] result = new long[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toLong(s[i]);
        }
        return result;
    }

    public static short[] toArrayShort(String... s) {
        short[] result = new short[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toShort(s[i]);
        }
        return result;
    }

    public static int[] toArrayInt(String... s) {
        int[] result = new int[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toInt(s[i]);
        }
        return result;
    }

    public static char[] toArrayChar(String... s) {
        char[] result = new char[s.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = toChar(s[i]);
        }
        // fixme a revoir
        return result;
    }

    private static final char[] HEX_CHARS = {'0', '1', '2', '3',
                                             '4', '5', '6', '7',
                                             '8', '9', 'a', 'b',
                                             'c', 'd', 'e', 'f',};

    /**
     * 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
     */
    public 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);
    }

    /**
     * Essai de convertir une chaine de caractere en une couleur si possible si
     * ce n'est pas possible retourne null.
     *
     * @param s la couleur sous la forme de string, par exemple "red",
     *          "yellow" ou bien en RGB "#FFAA99", et avec un canal alpha
     *          "#FFAA3366"
     * @return la couleur demandé si possible sinon null
     * @throws IllegalArgumentException FIXME
     * @throws StringUtilException      if any problem while conversion
     */
    public static Color toColor(String s) throws StringUtilException {
        try {
            if (s.startsWith("#")) {
                // récuperation des valeurs hexa
                String hr = s.substring(1, 3);
                String hg = s.substring(3, 5);
                String hb = s.substring(5, 7);

                // conversion en entier
                int r = Integer.parseInt(hr, 16);
                int g = Integer.parseInt(hg, 16);
                int b = Integer.parseInt(hb, 16);

                if (s.length() == 9) {
                    // s'il y a un canal alpha on l'utilise
                    String ha = s.substring(7, 9);
                    int a = Integer.parseInt(ha, 16);
                    return new Color(r, g, b, a);
                } else {
                    return new Color(r, g, b);
                }
            } else {
                Field f;
                f = Color.class.getField(s);
                return (Color) f.get(Color.class);
            }
        } catch (NumberFormatException e) {
            throw new StringUtilException(
                    "Error during conversion from string to color", e);
        } catch (SecurityException e) {
            throw new StringUtilException(
                    "Error during conversion from string to color", e);
        } catch (NoSuchFieldException e) {
            throw new StringUtilException(
                    "Error during conversion from string to color", e);
        } catch (IllegalArgumentException e) {
            throw new StringUtilException(
                    "Error during conversion from string to color", e);
        } catch (IllegalAccessException e) {
            throw new StringUtilException(
                    "Error during conversion from string to color", e);
        }
    }

    public static Date toDate(String s) throws ParseException {
        return DateFormat.getDateInstance().parse(s);
    }

    static final protected double[] timeFactors = {1000000, 1000, 60, 60, 24};

    static final protected String[] timeUnites = {"ns", "ms", "s", "m", "h",
                                                  "d"};

    /**
     * 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);
    }

    static final protected double[] memoryFactors = {1024, 1024, 1024, 1024};

    static final protected String[] memoryUnites = {"o", "Ko", "Mo", "Go",
                                                    "To"};

    /**
     * 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 facotrs 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;
    }

    /**
     * Vérifie q'une chaine de caractère est valid pour les bloc openner closer, ie.
     *
     * que les blocs définit par les deux caractères s'entrechevauchent pas.
     *
     * Exemple avec '(' ')' :
     *
     * (a(b)) est valide, par contre ((aaa))) n'est pas valide
     *
     * @param txt    txte a verifier
     * @param opener le caractère ouvrant
     * @param closer le caractère fermant
     * @return {@code true} is la chaine est valide
     */
    public static boolean checkEnclosure(String txt, char opener, char closer) {
        if (txt.indexOf(opener) == -1 && txt.indexOf(closer) == -1) {
            // ok pas de block détectés
            return true;
        }
        List opens = new ArrayList();
        for (int i = 0; i < txt.length(); i++) {
            char c = txt.charAt(i);
            if (c == opener) {
                // add a open block                
                opens.add(i);
                continue;
            }
            if (c == closer) {
                if (opens.isEmpty()) {
                    // problem no block left
                    return false;
                }
                // on supprime le dernier bloc
                opens.remove(opens.size() - 1);
            }
        }
        return opens.isEmpty();
    }

    /**
     * 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;
    }

    /**
     * Convert a String to MD5.
     *
     * @param toEncode string concerned
     * @return md5 corresponding
     * @throws IllegalStateException if could not found algorithm MD5
     */
    public static String encodeMD5(String toEncode) {

        byte[] uniqueKey = toEncode.getBytes();
        byte[] hash;
        // on récupère un objet qui permettra de crypter la chaine
        hash = MD5InputStream.getMD5Digest().digest(uniqueKey);
//        hash = MessageDigest.getInstance("MD5").digest(uniqueKey);

        StringBuilder hashString = new StringBuilder();
        for (byte aHash : hash) {
            String hex = Integer.toHexString(aHash);
            if (hex.length() == 1) {
                hashString.append("0");
                hashString.append(hex.charAt(hex.length() - 1));
            } else {
                hashString.append(hex.substring(hex.length() - 2));
            }
        }
        return hashString.toString();
    }

    /**
     * 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) {
        String result;

        try {
            MessageDigest sha1Md = MessageDigest.getInstance("SHA-1");

            byte[] digest = sha1Md.digest(toEncode.getBytes());
            result = asHex(digest);
        } catch (NoSuchAlgorithmException ex) {
            throw new IllegalStateException("Can't find SHA-1 message digest algorithm", ex);
        }

        return result;
    }

    /**
     *
     * @return the file separator escaped for a regex regarding the os used.
     */
    public static String getFileSeparatorRegex() {
        String result;
        if(SystemUtils.IS_OS_WINDOWS) {
            result = "\\\\";
        } else {
            result = "/";
        }
        return result;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy