com.silverpeas.util.StringUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.silverpeas.util.StringUtil.java

Source

  /**
   * Copyright (C) 2000 - 2013 Silverpeas
   *
   * This program is free software: you can redistribute it and/or modify it under the terms of the
   * GNU Affero General Public License as published by the Free Software Foundation, either version 3
   * of the License, or (at your option) any later version.
   *
   * As a special exception to the terms and conditions of version 3.0 of the GPL, you may
   * redistribute this Program in connection with Free/Libre Open Source Software ("FLOSS")
   * applications as described in Silverpeas's FLOSS exception. You should have received a copy of the
   * text describing the FLOSS exception, and it is also available here:
   * "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
   *
   * 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
   * Affero General Public License for more details.
   *
   * You should have received a copy of the GNU Affero General Public License along with this program.
   * If not, see <http://www.gnu.org/licenses/>.
   */
  package com.silverpeas.util;

  import com.ibm.icu.text.CharsetDetector;
  import com.ibm.icu.text.CharsetMatch;
  import com.silverpeas.util.i18n.I18NHelper;
  import org.apache.commons.codec.DecoderException;
  import org.apache.commons.codec.binary.Base64;
  import org.apache.commons.codec.binary.Hex;
  import org.apache.commons.lang3.CharEncoding;
  import org.apache.commons.lang3.StringUtils;

  import javax.mail.internet.AddressException;
  import javax.mail.internet.InternetAddress;
  import java.io.UnsupportedEncodingException;
  import java.nio.charset.Charset;
  import java.text.NumberFormat;
  import java.text.ParseException;
  import java.util.Arrays;
  import java.util.LinkedHashSet;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  import java.util.regex.Pattern;

  public class StringUtil extends StringUtils {

      public static String newline = System.getProperty("line.separator");

private static final char[] PUNCTUATION
    = new char[]{'&', '\"', '\'', '{', '(', '[', '-', '|', '`',
      '_', '\\', '^', '@', ')', ']', '=', '+', '}', '?', ',', '.', ';', '/', ':', '!', '',
      '%', '*', '$', '', '', '', '', '', ''};
      private static final String PATTERN_START = "{";
      private static final String PATTERN_END = "}";
      private static final String TRUNCATED_TEXT_SUFFIX = "...";
      private static final String EMAIL_PATTERN = "^[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,4}$";
      private static final String HOUR_PATTERN = "^([0-1]?[0-9]|2[0-4]):([0-5][0-9])(:[0-5][0-9])?$";

      public static boolean isDefined(String parameter) {
          return (parameter != null && !parameter.trim().isEmpty() && !"null".equalsIgnoreCase(parameter));
      }

      public static boolean isNotDefined(String parameter) {
          return !isDefined(parameter);
      }

      /**
       * <p>Returns either the passed in String, or if the String is
       * {@code not defined}, an empty String ("").</p>
       * <p/>
       * <pre>
       * StringUtil.defaultStringIfNotDefined(null)   = ""
       * StringUtil.defaultStringIfNotDefined("")     = ""
       * StringUtil.defaultStringIfNotDefined("    ") = ""
       * StringUtil.defaultStringIfNotDefined("bat")  = "bat"
       * </pre>
       * @param string the String to check, may be null, blank or filled by spaces
       * if the input is {@code not defined}, may be null, blank or filled by spaces
       * @return the passed in String, or the default if it was {@code null}
       * @see StringUtil#isNotDefined(String)
       * @see StringUtils#defaultString(String, String)
       */
      public static String defaultStringIfNotDefined(String string) {
          return defaultStringIfNotDefined(string, EMPTY);
      }

      /**
       * <p>Returns either the passed in String, or if the String is
       * {@code not defined}, the value of {@code defaultString}.</p>
       * <p/>
       * <pre>
       * StringUtil.defaultStringIfNotDefined(null, "NULL")   = "NULL"
       * StringUtil.defaultStringIfNotDefined("", "NULL")     = "NULL"
       * StringUtil.defaultStringIfNotDefined("    ", "NULL") = "NULL"
       * StringUtil.defaultStringIfNotDefined("bat", "NULL")  = "bat"
       * </pre>
       * @param string the String to check, may be null, blank or filled by spaces
       * @param defaultString the default String to return
       * if the input is {@code not defined}, may be null, blank or filled by spaces
       * @return the passed in String, or the default if it was {@code null}
       * @see StringUtil#isNotDefined(String)
       * @see StringUtils#defaultString(String, String)
       */
      public static String defaultStringIfNotDefined(String string, String defaultString) {
          return defaultString((isDefined(string) ? string : null), defaultString);
      }

      public static boolean isInteger(String id) {
          try {
              Integer.parseInt(id);
              return true;
          } catch (NumberFormatException e) {
              return false;
          }
      }

      public static boolean isLong(String id) {
          try {
              Long.parseLong(id);
              return true;
          } catch (NumberFormatException e) {
              return false;
          }
      }

      public static float convertFloat(String value) {
          if (StringUtil.isFloat(value)) {
              return Float.valueOf(value);
          } else if (value != null) {
              String charge = value.replace(',', '.');
              if (StringUtil.isFloat(charge)) {
                  return Float.valueOf(charge);
              }
          }
          return 0f;
      }

      public static boolean isFloat(String id) {
          try {
              Float.parseFloat(id);
              return true;
          } catch (NumberFormatException e) {
              return false;
          }
      }

      /**
       * @param text
       * @return a String with all quotes replaced by spaces
       */
      public static String escapeQuote(String text) {
          return text.replaceAll("'", " ");
      }

      /**
       * Replaces
       *
       * @param name
       * @return a String with all quotes replaced by spaces
       */
      public static String toAcceptableFilename(String name) {
          String fileName = name;
          fileName = fileName.replace('\\', '_');
          fileName = fileName.replace('/', '_');
          fileName = fileName.replace('$', '_');
          fileName = fileName.replace('%', '_');
          fileName = fileName.replace('?', '_');
          fileName = fileName.replace(':', '_');
          fileName = fileName.replace('*', '_');
          fileName = fileName.replace('"', '_');
          fileName = fileName.replace('<', '_');
          fileName = fileName.replace('>', '_');
          fileName = fileName.replace('|', '_');
          return fileName;
      }

      /**
       * Format a string by extending the principle of the the method format() of the class
       * java.text.MessageFormat to string arguments. For instance, the string '{key}' contained in the
       * original string to format will be replaced by the value corresponding to this key contained
       * into the values map.
       *
       * @param label The string to format
       * @param values The values to insert into the string
       * @return The formatted string, filled with values of the map.
       */
      public static String format(String label, Map<String, ?> values) {
          StringBuilder sb = new StringBuilder();
          int startIndex = label.indexOf(PATTERN_START);
          int endIndex;
          String patternKey;
          Object value;
          while (startIndex != -1) {
              endIndex = label.indexOf(PATTERN_END, startIndex);
              if (endIndex != -1) {
                  patternKey = label.substring(startIndex + 1, endIndex);
                  if (values.containsKey(patternKey)) {
                      value = values.get(patternKey);
                      sb.append(label.substring(0, startIndex)).append(value != null ? value.toString() : "");
                  } else {
                      sb.append(label.substring(0, endIndex + 1));
                  }
                  label = label.substring(endIndex + 1);
                  startIndex = label.indexOf(PATTERN_START);
              } else {
                  sb.append(label);
                  label = "";
                  startIndex = -1;
              }
          }
          sb.append(label);
          return sb.toString();
      }

      /**
       * @param text The string to truncate if its size is greater than the maximum length given as
       * parameter.
       * @param maxLength The maximum length required.
       * @return The truncated string followed by '...' if needed. Returns the string itself if its
       * length is smaller than the required maximum length.
       */
      public static String truncate(String text, int maxLength) {
          if (text == null || text.length() <= maxLength) {
              return text;
          } else if (maxLength <= 3) {
              return TRUNCATED_TEXT_SUFFIX;
          } else {
              return text.substring(0, maxLength - 3) + TRUNCATED_TEXT_SUFFIX;
          }
      }

      /**
       * Replace parts of a text by an one replacement string. The text to replace is specified by a
       * regex.
       * @param source the original text
       * @param regex the regex that permits to identify parts of text to replace
       * @param replacement the replacement text
       * @return The source text modified
       */
      public static String regexReplace(String source, String regex, String replacement) {
          if (StringUtil.isNotDefined(source) || StringUtil.isNotDefined(regex)) {
              return source;
          }
          return source.replaceAll(regex, replacement);
      }

      /**
       *
       * Validate the form of an email address. <P> Return <tt>true</tt> only if <ul> <li>
       * <tt>aEmailAddress</tt> can successfully construct an
       * {@link javax.mail.internet.InternetAddress} <li>when parsed with "
       *
       * @" as delimiter, <tt>aEmailAddress</tt> contains two tokens which satisfy
       * {@link hirondelle.web4j.util.Util#textHasContent}. </ul> <P> The second condition arises since
       * local email addresses, simply of the form "<tt>albert</tt>", for example, are valid for
       * {@link javax.mail.internet.InternetAddress}, but almost always undesired.
       *
       * @param aEmailAddress the address to be validated
       * @return true is the address is a valid email address - false otherwise.
       */
      public static boolean isValidEmailAddress(String aEmailAddress) {
          if (aEmailAddress == null) {
              return false;
          }
          boolean result;
          try {
              new InternetAddress(aEmailAddress);
              result = Pattern.matches(EMAIL_PATTERN, aEmailAddress);
          } catch (AddressException ex) {
              result = false;
          }
          return result;
      }

      public static boolean isValidHour(final String time) {
          if (!isDefined(time)) {
              return false;
          }
          return Pattern.matches(HOUR_PATTERN, time);
      }

      public static String convertToEncoding(String toConvert, String encoding) {
          try {
              return new String(toConvert.getBytes(Charset.defaultCharset()), encoding);
          } catch (UnsupportedEncodingException ex) {
              return toConvert;
          }
      }

      /**
       * Evaluate the expression and return true if expression equals "true", "yes", "y", "1" or "oui".
       *
       * @param expression the expression to be evaluated
       * @return true if expression equals "true", "yes", "y", "1" or "oui".
       */
      public static boolean getBooleanValue(final String expression) {
          return "true".equalsIgnoreCase(expression) || "yes".equalsIgnoreCase(expression)
                  || "y".equalsIgnoreCase(expression) || "oui".equalsIgnoreCase(expression)
                  || "1".equalsIgnoreCase(expression);
      }

      /**
       * Method for trying to detect encoding
       *
       * @param data some data to try to detect the encoding.
       * @param declaredEncoding expected encoding.
       * @return
       */
      public static String detectEncoding(byte[] data, String declaredEncoding) {
          CharsetDetector detector = new CharsetDetector();
          if (!StringUtil.isDefined(declaredEncoding)) {
              detector.setDeclaredEncoding(CharEncoding.ISO_8859_1);
          } else {
              detector.setDeclaredEncoding(declaredEncoding);
          }
          detector.setText(data);
          CharsetMatch detectedEnc = detector.detect();
          return detectedEnc.getName();
      }

      /**
       * Method for trying to detect encoding
       *
       * @param data some data to try to detect the encoding.
       * @param declaredEncoding expected encoding.
       * @return
       */
      public static String detectStringEncoding(byte[] data, String declaredEncoding)
              throws UnsupportedEncodingException {
          if (data != null) {
              String value = new String(data, declaredEncoding);
              if (!checkEncoding(value)) {
                  Set<String> supportedEncodings;
                  if (CharEncoding.UTF_8.equals(declaredEncoding)) {
                      supportedEncodings = StringUtil.detectMaybeEncoding(data, CharEncoding.ISO_8859_1);
                  } else {
                      supportedEncodings = StringUtil.detectMaybeEncoding(data, CharEncoding.UTF_8);
                  }
                  return reencode(data, supportedEncodings, declaredEncoding);
              }
          }
          return declaredEncoding;
      }

      private static boolean checkEncoding(String value) {
          if (value != null) {
              char[] chars = value.toCharArray();
              for (char currentChar : chars) {
                  if (!Character.isLetterOrDigit(currentChar) && !Character.isWhitespace(currentChar)
                          && !ArrayUtil.contains(PUNCTUATION, currentChar)) {
                      return false;
                  }
              }
          }
          return true;

      }

      private static String reencode(byte[] data, Set<String> encodings, String declaredEncoding)
              throws UnsupportedEncodingException {
          if (!encodings.isEmpty()) {
              String encoding = encodings.iterator().next();
              String value = new String(data, encoding);
              if (!checkEncoding(value)) {
                  encodings.remove(encoding);
                  return reencode(data, encodings, declaredEncoding);
              }
              return encoding;
          }
          return declaredEncoding;
      }

      /**
       * Method for trying to detect encoding
       *
       * @param data some data to try to detect the encoding.
       * @param declaredEncoding expected encoding.
       * @return
       */
      public static Set<String> detectMaybeEncoding(byte[] data, String declaredEncoding) {
          CharsetDetector detector = new CharsetDetector();
          if (!StringUtil.isDefined(declaredEncoding)) {
              detector.setDeclaredEncoding(CharEncoding.ISO_8859_1);
          } else {
              detector.setDeclaredEncoding(declaredEncoding);
          }
          detector.setText(data);
          CharsetMatch[] detectedEnc = detector.detectAll();
          Set<String> encodings = new LinkedHashSet<String>(detectedEnc.length);
          for (CharsetMatch detectedEncoding : detectedEnc) {
              encodings.add(detectedEncoding.getName());
          }
          return encodings;
      }

      /**
       * Indicates if two Strings are equals, managing null.
       *
       * @param s1 the first String.
       * @param s2 the second String.
       * @return true ifthe two Strings are equals.
       */
      public static boolean areStringEquals(String s1, String s2) {
          if (s1 == null) {
              return s2 == null;
          }
          return s1.equals(s2);
      }

      /**
       * Parse a String into a float using the default locale.
       *
       * @param value the string to be parsed into a float.
       * @return the float value.
       * @throws ParseException
       */
      public static float floatValue(String value) throws ParseException {
          return floatValue(value, I18NHelper.defaultLanguage);
      }

      /**
       * Parse a String into a float using the specified locale.
       *
       * @param value the string to be parsed into a float
       * @param language the language for defining the locale
       * @return the float value.
       * @throws ParseException
       */
      public static float floatValue(String value, String language) throws ParseException {
          String lang = language;
          if (!StringUtil.isDefined(language)) {
              lang = I18NHelper.defaultLanguage;
          }
          NumberFormat numberFormat = NumberFormat.getInstance(new Locale(lang));
          return numberFormat.parse(value).floatValue();
      }

      /**
       * Encodes the specified binary data into a text of Base64 characters.
       *
       * @param binaryData the binary data to convert in Base64-based String.
       * @return a String representation of the binary data in Base64 characters.
       */
      public static String asBase64(byte[] binaryData) {
          return Base64.encodeBase64String(binaryData);
      }

      /**
       * Decodes the specified text with Base64 characters in binary.
       *
       * @param base64Text the text in Base64.
       * @return the binary representation of the text.
       */
      public static byte[] fromBase64(String base64Text) {
          return Base64.decodeBase64(base64Text);
      }

      /**
       * Encodes the specified binary data into a String representing the hexadecimal values of each
       * byte in order. The String is in the UTF-8 charset.
       *
       * @param binaryData the binary data to concert in hexadecimal-based String.
       * @return a String representation of the binary data in Hexadecimal characters.
       */
      public static String asHex(byte[] binaryData) {
          return Hex.encodeHexString(binaryData);
      }

      /**
       * Decodes the specified text with hexadecimal values in bytes of those same values. The text is
       * considered to be in the UTF-8 charset.
       *
       * @param hexText the text with hexadecimal-based characters.
       * @return the binary representation of the text.
       * @throws ParseException if an odd number or illegal of characters is supplied.
       */
      public static byte[] fromHex(String hexText) throws ParseException {
          try {
              return Hex.decodeHex(hexText.toCharArray());
          } catch (DecoderException ex) {
              throw new ParseException(ex.getMessage(), -1);
          }
      }

      /**
       * <p>Splits the provided text into an array, using whitespace as the separator. Whitespace is
       * defined by {@link Character#isWhitespace(char)}.</p>
       *
       * <p>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.</p>
       *
       * <p>A {@code null} input String returns {@code null}.</p>
       *
       * <pre>
       * StringUtils.split(null)       = null
       * StringUtils.split("")         = empty list
       * StringUtils.split("abc def")  = ["abc", "def"]
       * StringUtils.split("abc  def") = ["abc", "def"]
       * StringUtils.split(" abc ")    = ["abc"]
       * </pre>
       *
       * @param str the String to parse, may be null
       * @return an array of parsed Strings, {@code null} if null String input
       */
      public static Iterable<String> splitString(String str) {
          return Arrays.asList(split(str));
      }

      /**
       * <p>Splits the provided text into an array, separator specified. This is an alternative to using
       * StringTokenizer.</p>
       *
       * <p>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.</p>
       *
       * <p>A {@code null} input String returns {@code null}.</p>
       *
       * <pre>
       * StringUtils.split(null, *)         = null
       * StringUtils.split("", *)           = empty list
       * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
       * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
       * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
       * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
       * </pre>
       *
       * @param str the String to parse, may be null
       * @param separatorChar the character used as the delimiter
       * @return an array of parsed Strings, {@code null} if null String input
       */
      public static Iterable<String> splitString(String str, char separatorChar) {
          return Arrays.asList(split(str, separatorChar));
      }

      private StringUtil() {
      }
  }