Java tutorial
/* * Copyright (c) 2015 Hewlett-Packard Development Company, L.P. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.didm.tools.utils; import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class StringUtils { /** The platform dependent line separator (new line character). */ public static final String EOL = System.getProperty("line.separator"); /** The tab character. */ public static final String TAB = "\t"; /** The empty string. */ public static final String EMPTY = ""; /** The underscore character. */ public static final String UNDERSCORE = "_"; /** The zero ("0") character as a string. */ public static final String ZERO = "0"; /** The comma (",") character as a string. */ public static final String COMMA = ","; /** String representing UTF-8 encoding (e.g. String.getBytes(UTF8)) */ public static final String UTF8 = "UTF-8"; /** Format token used for parameter replacement. */ private static final String FORMAT_TOKEN = "{}"; /** String representation of null. */ private static final String NULL_REP = "{null}"; private static final char SPACE = ' '; /** regular expression for identifiers. */ private static final Pattern ID_REGEXP = Pattern.compile("[A-Z][A-Z0-9_\\.]*", Pattern.CASE_INSENSITIVE); private static final String E_INVALID_ID = "identifier must begin with a letter and may be followed by " + "zero or more letters, numbers, underscores, and/or dots"; private static final String E_NULL_PARAM = "parameter cannot be null"; private static final String E_NOT_UPPER_FORMAT = "string must consist of only uppercase letters, digits, and/or" + "underscores, beginning with a letter or underscore"; private static final String E_NOT_CAMEL_CASE = "string must consist of only letters and digits, starting " + "with a letter"; // matches string form of "0" to "255" (and nothing else) private static final String RE_0_TO_255 = "([01]?\\d\\d?|2[0-4]\\d|25[0-5])"; // start with a letter, followed by zero or more letters or digits private static final String RE_ALPHA_NUMERIC = "[A-Za-z][A-Za-z0-9]*"; // start with a letter or underscore, followed by zero or more // letters, digits or underscores private static final String RE_ALPHA_NUMERIC_UNDERSCORES = "[A-Za-z_][A-Za-z0-9_]*"; // start with uppercase letter or underscore, followed by zero or more // uppercase letters, digits or underscores private static final String RE_UPPER_ALPHA_NUMERIC_UNDERSCORES = "[A-Z_][A-Z0-9_]*"; // matches one or more lowercase letters private static final String RE_LOWER_ALPHA = "[a-z]+"; // required for proper use of toUpperCase/toLowerCase private static final Locale LOCALE = Locale.getDefault(); // no instantiation private StringUtils() { } /** This predicate returns true if the specified parameter is null, or * consists only of whitespace. * * @param value the string value to test * @return true if the value is null, or empty */ public static boolean isEmpty(String value) { return value == null || value.trim().length() == 0; } /** * Safely invokes {@code toString} on the specified entity and returns the * result, unless the specified object is null, in which case it will * return null. * * @param o object on which to invoke toString * @return result of {@code o.toString()} invocation or null if the object * is null */ public static String safeToString(Object o) { return o == null ? null : o.toString(); } /** This predicate returns true if the specified string is alpha numeric; * that is to say, if it begins with a letter and consists only of letters * and numbers. Underscores are allowed if the second parameter is set true. * * @param value the string value to test * @param allowUnderscores if true, underscores are allowed * @return true if the value is alphanumeric * @throws NullPointerException if value is null */ public static boolean isAlphaNumeric(String value, boolean allowUnderscores) { return value.matches(allowUnderscores ? RE_ALPHA_NUMERIC_UNDERSCORES : RE_ALPHA_NUMERIC); } /** This predicate returns true if the specified string is alpha numeric; * that is to say, if it begins with a letter and consists only of letters, * numbers and underscores. * * @param value the string value to test * @return true if the value is alphanumeric * @throws NullPointerException if value is null */ public static boolean isAlphaNumeric(String value) { return isAlphaNumeric(value, true); } /** Returns the given value wrapped in double-quote characters (") if the * value is not null, or the string {@code "null"} if it is null. * * @param value the value * @return the string quoted (if not null), or "null" */ public static String quoted(String value) { return value == null ? "null" : "\"" + value + "\""; } /** A convenience overloaded method for {@link #toCamelCase(String)} * which takes enumeration constants as the parameter. * @param e the enum constant * @return the name of the enum constant, camel-cased */ public static String toCamelCase(Enum<?> e) { return toCamelCase(e.name()); } /** * This method expects an input string consisting of uppercase letters, * digits, and underscores (the standard format for constant names), and * converts it to "camelCase". * <p> * For example, {@code "LORD_OF_THE_RINGS"} becomes * {@code "lordOfTheRings"}. * * @param s the uppercase words delimited by underscores input string * @return the input string converted to camelCase * @throws NullPointerException if the parameter is null * @throws IllegalArgumentException if s has unexpected (or no) characters * in it */ public static String toCamelCase(String s) { return toCamelCase(EMPTY, s); } /** * A convenience overloaded method for * {@link #toCamelCase(String, String)}, which uses {@code e.name()}. * * @param prefix optional prefix * @param e the enum constant * @return the name of the enum constant, camel-cased */ public static String toCamelCase(String prefix, Enum<?> e) { return toCamelCase(prefix, e.name()); } /** * This method expects a string consisting of uppercase letters, digits, * and underscores (the standard format for constant names), and converts * it to "camelCase". If a prefix is specified, i.e. is not null or empty * string, it will be prepended as-is. * <p> * For example: * <pre> * "LORD_OF_THE_RINGS" - "lordOfTheRings" * "LORD_OF_THE_RINGS" and prefix "prequelTo" - "prequelToLordOfTheRings" * </pre> * * @param prefix optional prefix * @param s the uppercase words delimited by underscores input string * @return the input string converted to camelCase * @throws NullPointerException if the parameter is null * @throws IllegalArgumentException if s has unexpected (or no) characters * in it */ public static String toCamelCase(String prefix, String s) { if (s == null) throw new NullPointerException(E_NULL_PARAM); if (!s.matches(RE_UPPER_ALPHA_NUMERIC_UNDERSCORES)) throw new IllegalArgumentException(E_NOT_UPPER_FORMAT); String p = prefix != null ? prefix : EMPTY; StringBuilder sb = new StringBuilder(p); String[] words = s.split("_"); for (String w : words) { if (w.length() > 0) { String lc = w.toLowerCase(Locale.getDefault()); if (sb.length() > 0) { sb.append(w.charAt(0)).append(lc.substring(1)); } else { sb.append(lc); } } } return sb.toString(); } // matches zero or more lowercase letters (group 1), followed by // exactly one uppercase letter or digit (group 2) private static final Pattern P_LOWER_UPPER = Pattern.compile("([a-z]*)([A-Z0-9])"); // matches zero or more lowercase letters (group 1) at the end of the string private static final Pattern P_LOWER_SUFFIX = Pattern.compile("([a-z]*)$"); /** This method expects an input string consisting of letters and digits * in "camelCase" (the standard format for variable names), and converts * it to uppercase letters with underscore delimiters between the words. * <p> * For example, {@code "lordOfTheRings"} becomes * {@code "LORD_OF_THE_RINGS"}. * * @param cc the camelCase input string * @return the input string converted to uppercase words delimited * by underscores * @throws NullPointerException if the parameter is null * @throws IllegalArgumentException if s has unexpected (or no) characters * in it */ public static String fromCamelCase(String cc) { if (cc == null) throw new NullPointerException(E_NULL_PARAM); if (!cc.matches(RE_ALPHA_NUMERIC)) throw new IllegalArgumentException(E_NOT_CAMEL_CASE); String result; if (cc.matches(RE_LOWER_ALPHA)) { // if string is just lowercase letters, simply convert to uppercase result = cc.toUpperCase(LOCALE); } else { StringBuilder sb = new StringBuilder(); // matcher to match successive groups of "[xxxx]X" // (optional lowercase letters; one uppercase letter or digit) Matcher m = P_LOWER_UPPER.matcher(cc); if (m != null) { while (m.find()) { String lower = m.group(1); String upper = m.group(2); sb.append(lower.toUpperCase(LOCALE)).append(UNDERSCORE).append(upper); } } // don't forget trailing lowercase letters m = P_LOWER_SUFFIX.matcher(cc); if (m != null) { m.find(); sb.append(m.group(1).toUpperCase(LOCALE)); } result = sb.toString(); } return result; } /** This predicate returns true if the specified string, when converted * to an int, lies in the range 0 - 255. Leading zeroes are allowed. * * @param value the string value to test * @return true if the value is "0" - "255" * @throws NullPointerException if value is null */ public static boolean isIntegerZeroTo255(String value) { return value.matches(RE_0_TO_255); } /** This predicate returns true if the supplied string matches the regular * expression defined for general identifiers. That is to say, the string * starts with letter, and is followed by zero or more letters, numbers, * underscores, and/or dots. * * @param id the identifier * @return true if it is well-formed */ public static boolean isStandardIdentifier(String id) { return ID_REGEXP.matcher(id).matches(); } /** This method checks the supplied string to see that it matches the * regular expression defined for general identifiers. That is to say, * the string starts with letter, and is followed by zero or more letters, * numbers, underscores, and/or dots. If it matches, the method silently * returns. If it does not match, an exception is thrown. * * @param id the identifier * @throws IllegalArgumentException if the string does not match the * pattern for standard identifiers. */ public static void validateStandardIdentifier(String id) { if (!ID_REGEXP.matcher(id).matches()) throw new IllegalArgumentException(E_INVALID_ID); } /** * Determine if two Strings, considering nulls to be identical, are equal. * * @param one the first String to compare * @param two the second String to compare * @return true if the Strings are identical, including if both are null, * and false otherwise */ public static boolean equals(String one, String two) { return (((one != null) && (two != null) && one.equals(two)) || ((one == null) && (two == null))); } /** * Returns either the correctly parsed hex value (as an int) or the * supplied fallback value. * * @param hex String to parse as a hex value * @param fallback The int to return if the supplied hex string is invalid * @return the hex value */ public static int parseHex(String hex, int fallback) { int result; try { result = Integer.parseInt(hex, 16); } catch (NumberFormatException nfe) { result = fallback; } return result; } /** * Returns either the correctly parsed int value or the supplied * fallback value. * * @param value String to parse as an int * @param fallback The int to return if the supplied string is invalid * @return the int value */ public static int parseInt(String value, int fallback) { int result; try { result = Integer.parseInt(value); } catch (NumberFormatException nfe) { result = fallback; } return result; } /** * Returns a zero-filled string. For example: * <pre> * StringUtils.zeroFill(45, 6); * </pre> * returns the string {@code "000045"}. * * @param value the value * @param fieldWidth the field width * @return the zero filled string */ public static String zeroFill(int value, int fieldWidth) { StringBuilder buf = new StringBuilder(); buf.append(value); while (buf.length() < fieldWidth) { buf.insert(0, ZERO); } return buf.toString(); } /** * A simple string formatter that replaces each occurrence of * <code>{}</code> in the format string with the string representation * of each of the subsequent, optional arguments. * For example: * <pre> * StringUtils.format("{} = {}", "Foo", 123); * // returns "Foo = 123" * </pre> * * @param fmt the format string * @param o arguments to be inserted into the output string * @return a formatted string */ public static String format(String fmt, Object... o) { if (fmt == null) throw new NullPointerException("null format string"); if (o.length == 0) return fmt; // Format the message using the format string as the seed. // Stop either when the list of objects is exhausted or when // there are no other place-holder tokens. final int ftlen = FORMAT_TOKEN.length(); int i = 0; int p = -1; String rep; StringBuilder sb = new StringBuilder(fmt); while (i < o.length && (p = sb.indexOf(FORMAT_TOKEN, p + 1)) >= 0) { rep = o[i] == null ? NULL_REP : o[i].toString(); sb.replace(p, p + ftlen, rep); i++; } return sb.toString(); } /** * Formats the supplied strings so that they are arranged in neat columns. * * @param strings the array of strings to format * @param maxWidth the maximum number of characters any single line can be * @param colSpacing the number of spaces between columns * @param indent number of spaces to indent the whole thing by * @return a string (with embedded newlines) that is the columnized result */ public static String columnize(String[] strings, int maxWidth, int colSpacing, int indent) { // a little sanity checking.. if (strings == null || strings.length == 0) return EMPTY; final String indenter = pad(EMPTY, indent); final String spacer = pad(EMPTY, colSpacing); // find the longest string.. int longest = 0; for (String s : strings) longest = (s.length() > longest ? s.length() : longest); // calc the number of columns.. int ncol = 1; int width = indent + longest; while (width < maxWidth) { width += colSpacing + longest; if (width <= maxWidth) ncol++; } int nrow = (strings.length + ncol - 1) / ncol; StringBuilder result = new StringBuilder(); for (int r = 0; r < nrow; r++) { int d = 0; while (r + d < strings.length) { result.append(d == 0 ? indenter : spacer); result.append(pad(strings[r + d], longest)); d += nrow; } result.append(EOL); } return result.toString(); } /** * Formats the supplied strings so that they are arranged in * neat columns, but with no indent. * * @param strings the array of strings to format * @param maxWidth the maximum number of characters any single line can be * @param colSpacing the number of spaces between columns * @return the columnized strings */ public static String columnize(String[] strings, int maxWidth, int colSpacing) { return columnize(strings, maxWidth, colSpacing, 0); } /** * Formats the supplied strings so that they are arranged in * neat columns; space between columns is 2; no indent. * * @param strings the array of strings to format * @param maxWidth the maximum number of characters any single line can be * @return the columnized strings */ public static String columnize(String[] strings, int maxWidth) { return columnize(strings, maxWidth, 2, 0); } /** * Formats the supplied strings so that they are arranged in * neat columns; maximum line width is 78; space between columns is 2; * no indent. * * @param strings the array of strings to format * @return the columnized strings */ public static String columnize(String[] strings) { return columnize(strings, 78, 2, 0); } /** Enumeration for alignment. */ public static enum Align { LEFT, CENTER, RIGHT } /** * Pads a field to the specified field width. If what is longer than * width, it is truncated, unless the noTruncate flag is set true. * * @param what the string to be padded * @param width the width of the padded (truncated) field * @param with the character to pad with * @param align the alignment * @param noTruncate do not truncate the string if it is longer than width * @return the padded string */ public static String pad(String what, int width, char with, Align align, boolean noTruncate) { if (what.length() >= width) return noTruncate ? what : what.substring(0, width); StringBuilder sb = new StringBuilder(what); int insertPos = (align == Align.RIGHT) ? 0 : sb.length(); while (sb.length() < width) { sb.insert(insertPos, with); if (align == Align.CENTER) { // flip insert pos to other side insertPos = (insertPos == 0 ? sb.length() : 0); } } return sb.toString(); } /** * Pads a field to the specified field width. If what is longer than width, * it is truncated. * * @param what the string to be padded * @param width the width of the padded (truncated) field * @param with the character to pad with * @param align the alignment * @return the padded string */ public static String pad(String what, int width, char with, Align align) { return pad(what, width, with, align, false); } /** * Pads a field to the specified field width. If what is longer than width, * it is truncated. The text is LEFT justified. * * @param what the string to be padded * @param width the width of the padded (truncated) field * @param with the character to pad with * @return the padded string */ public static String pad(String what, int width, char with) { return pad(what, width, with, Align.LEFT, false); } /** * Pads a field to the specified field width. If what is longer than width, * it is truncated. Space is used as the padding character. * * @param what the string to be padded * @param width the width of the padded (truncated) field * @param align one of LEFT, CENTER or RIGHT * @return the padded string */ public static String pad(String what, int width, Align align) { return pad(what, width, SPACE, align, false); } /** * Pads a field to the specified field width. If what is longer than width, * it is truncated. The text is LEFT justified. Space is used as the * padding character. * * @param what the string to be padded * @param width the width of the padded (truncated) field * @return the padded string */ public static String pad(String what, int width) { return pad(what, width, SPACE, Align.LEFT, false); } /** Returns a string of spaces of the specified length. * * @param length the length * @return a string of spaces */ public static String spaces(int length) { return pad("", length); } /** * Returns a comma-separated string of the items in the collection. The * individual tokens within the string are produced using * {@code Object#toString()} on each item in the collection. * * @param items collection of items * @return comma-separated string of items in the collection; empty string * if the collection is empty; null if the collection is null */ public static String commaSeparated(Collection<?> items) { return join(items, COMMA); } /** * Convert the given string to null, if it is already null or is empty. * * @param s string to be verified * @return null if the string is null or empty; otherwise the unmodified * string */ public static String emptyIsNull(String s) { return s == null || s.length() == 0 ? null : s; } /** * Convert the given string to null, if it is already null or is empty if * trimmed. * * @param s string to be verified * @return null if the string is null or empty; otherwise the unmodified * string */ public static String trimmedEmptyIsNull(String s) { return s == null || s.trim().length() == 0 ? null : s; } /** * Convert the given string to an empty string, if it is null. * * @param s string to be verified * @return empty string if the string is null; otherwise the unmodified * string */ public static String nullIsEmpty(String s) { return s == null ? EMPTY : s; } /** * Removes any punctuation in the passed in string. * * @param value the original string value that may contain punctuation * @return true new string with the punctuation removed * @throws NullPointerException if value is null */ public static String trimPunct(String value) { return value.replaceAll("\\p{Punct}+", ""); } /** * Removes any punctuation and whitespace in the passed in string. * * @param value the original string value that may contain punctuation * @param replace string to be replaced instead of punctuation and * white space * @return true new string with the punctuation removed * @throws NullPointerException if value is null */ public static String trimPunctAndSpaceWith(String value, String replace) { return value.replaceAll("\\W", replace); } /** Default delimiter for the {@link #join} methods. */ public static final String DEFAULT_JOIN_DELIMITER = ", "; /** * Joins a collection of objects' toString() values into a single string, * using the default delimiter of ", " (comma-space). * * @param values the values * @return the delimiter-separated string */ public static String join(Collection<?> values) { if (values == null) return null; return join(values.toArray(new Object[values.size()])); } /** * Joins an array of objects' toString() values into a single string, * using the default delimiter of ", " (comma-space). * * @param values the values * @return the delimiter-separated string */ public static String join(Object[] values) { return join(values, DEFAULT_JOIN_DELIMITER); } /** * Joins a collection of objects' toString() values into a single string, * using the given delimiter. If the collection is null, null is returned. * * @param values the values * @param delim the delimiter * @return the delimiter-separated string */ public static String join(Collection<?> values, String delim) { if (values == null) return null; return join(values.toArray(new Object[values.size()]), delim); } /** * Joins an array of objects' toString() values into a single string, * using the given delimiter. If the array is null, null is returned. * * @param values the values * @param delim the delimiter * @return the delimiter-separated string */ public static String join(Object[] values, String delim) { if (values == null) return null; StringBuilder sb = new StringBuilder(); for (Object v : values) { if (sb.length() > 0) sb.append(delim); sb.append(v); } return sb.toString(); } /** Concatenates an array of objects using a StringBuilder and its * {@code append()} method. This convenience method reduces something like: * <pre> * String s = new StringBuilder().append(e1).append(e2).append(e3).toString(); * </pre> * to * <pre> * String s = StringUtils.concat(e1, e2, e3); * </pre> * * @param values the values to concatenate * @return the concatentated string */ public static String concat(Object... values) { StringBuilder sb = new StringBuilder(); for (Object o : values) sb.append(o); return sb.toString(); } /** * Normalizes any compound line breaks (\r\n or \n\r) to only \n. * * @param string string to be normalized * @return normalized string */ public static String normalizeEOL(String string) { return string.replaceAll("(\n\r|\r\n|\r)", "\n"); } private static final Pattern RE_MULTLINE = Pattern.compile("^(.*)$", Pattern.MULTILINE); /** * Removes all lines that begin with the '#' character. * * @param s the multiline input * @return multiline output with "comment" lines removed */ public static String stripCommentLines(String s) { StringBuilder sb = new StringBuilder(); Matcher m = RE_MULTLINE.matcher(s); if (m != null) { while (m.find()) { String line = m.group(1); if (!line.startsWith("#")) { sb.append(line).append(EOL); } } } return sb.toString(); } /** * Read in the contents of a text file from the given path. If the * resource cannot be found, null is returned. * * @param path path of resource containing the data * @param classLoader class-loader to be used for locating resource * @return the contents of the file as a string * @throws IOException if there is a problem reading the file. */ public static String getFileContents(String path, ClassLoader classLoader) throws IOException { InputStream is = classLoader.getResourceAsStream(path); if (is == null) return null; String result = null; try { // use Apache Commons IOUtils to read byte array from input stream byte[] bytes = IOUtils.toByteArray(is); result = new String(bytes, UTF8).replaceAll("\0", ""); } finally { try { is.close(); } catch (IOException e) { // What to do, what to do? } } return result; } }