/* ================================================================== * StringUtils.java - Nov 1, 2012 1:55:45 PM * * Copyright 2007-2012 SolarNetwork.net Dev Team * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * ================================================================== */ package net.solarnetwork.util; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; /** * Common string helper utilities. * * @author matt * @version 1.3 */ public final class StringUtils { private StringUtils() { // don't construct me } /** * Get a comma-delimited string from a collection of objects. * * @param set * the set * @return the comma-delimited string * @see #delimitedStringFromCollection(Set, String) */ public static String commaDelimitedStringFromCollection(final Collection<?> set) { return delimitedStringFromCollection(set, ","); } /** * Get a delimited string from a collection of objects. * * <p> * This will call the {@link Object#toString()} method on each object in the * set, using the natural iteration ordering of the set.No attempt to escape * delimiters within the set's values is done. * </p> * * @param set * the set * @param delim * the delimiter * @return the delimited string */ public static String delimitedStringFromCollection(final Collection<?> set, String delim) { if ( set == null ) { return null; } if ( delim == null ) { delim = ""; } StringBuilder buf = new StringBuilder(); for ( Object o : set ) { if ( buf.length() > 0 ) { buf.append(delim); } if ( o != null ) { buf.append(o.toString()); } } return buf.toString(); } /** * Get a delimited string from a map of objects. * * <p> * This will call {@link #delimitedStringFromMap(Map, String, String)} using * a {@code =} key value delimiter and a {@code ,} pair delimiter. * </p> * * @param map * the map * @return the string */ public static String delimitedStringFromMap(final Map<?, ?> map) { return delimitedStringFromMap(map, "=", ","); } /** * Get a delimited string from a map of objects. * * <p> * This will call the {@link Object#toString()} method on each key and value * in the map, using the natural iteration ordering of the map. No attempt * to escape delimiters within the map's values is done. * </p> * * @param map * the map * @param keyValueDelim * the delimited to use between keys and values * @param pairDelim * the delimiter to use betwen key/value pairs * @return the string */ public static String delimitedStringFromMap(final Map<?, ?> map, String keyValueDelim, String pairDelim) { if ( map == null ) { return null; } StringBuilder buf = new StringBuilder(); for ( Map.Entry<?, ?> me : map.entrySet() ) { if ( buf.length() > 0 ) { buf.append(pairDelim); } if ( me.getKey() != null ) { buf.append(me.getKey().toString()); } buf.append(keyValueDelim); if ( me.getValue() != null ) { buf.append(me.getValue().toString()); } } return buf.toString(); } /** * Get a Set via a comma-delimited string value. * * @param list * the comma-delimited string * @return the Set, or <em>null</em> if {@code list} is <em>null</em> or an * empty string * @see #delimitedStringToSet(String, String) */ public static Set<String> commaDelimitedStringToSet(final String list) { return delimitedStringToSet(list, ","); } /** * Get a string Set via a delimited String value. * * <p> * The format of the {@code list} String should be a delimited list of * values. Whitespace is permitted around the delimiter, and will be * stripped from the values. Whitespace is also trimmed from the start and * end of the input string. The list order is preserved in the iteration * order of the returned Set. * </p> * * @param list * the delimited text * @param delim * the delimiter to split the list with * @return the Set, or <em>null</em> if {@code list} is <em>null</em> or an * empty string */ public static Set<String> delimitedStringToSet(final String list, final String delim) { if ( list == null || list.length() < 1 ) { return null; } String[] data = list.trim().split("\\s*" + Pattern.quote(delim) + "\\s*"); Set<String> s = new LinkedHashSet<String>(data.length); for ( String d : data ) { s.add(d); } return s; } /** * Get string Map via a comma-delimited String value. * * <p> * The format of the {@code mapping} String should be: * </p> * * <pre> * key=val[,key=val,...] * </pre> * * @param mapping * the delimited text * @see #delimitedStringToMap(String, String, String) */ public static Map<String, String> commaDelimitedStringToMap(final String mapping) { return delimitedStringToMap(mapping, ",", "="); } /** * Get a string Map via a delimited String value. * * <p> * The format of the {@code mapping} String should be: * </p> * * <pre> * key=val[,key=val,...] * </pre> * * <p> * The record and field delimiters are passed as parameters to this method. * Whitespace is permitted around all delimiters, and will be stripped from * the keys and values. Whitespace is also trimmed from the start and end of * the input string. * </p> * * @param mapping * the delimited text * @param recordDelim * the key+value record delimiter * @param fieldDelim * the key+value delimiter */ public static Map<String, String> delimitedStringToMap(final String mapping, final String recordDelim, final String fieldDelim) { if ( mapping == null || mapping.length() < 1 ) { return null; } final String[] pairs = mapping.trim().split("\\s*" + Pattern.quote(recordDelim) + "\\s*"); final Map<String, String> map = new LinkedHashMap<String, String>(); final Pattern fieldSplit = Pattern.compile("\\s*" + Pattern.quote(fieldDelim) + "\\s*"); for ( String pair : pairs ) { String[] kv = fieldSplit.split(pair); if ( kv == null || kv.length != 2 ) { continue; } map.put(kv[0], kv[1]); } return map; } /** * Create an array of regular expressions from strings. If * {@code expressions} is <em>null</em> or empty, the result will be * <em>null</em>. Pass {@bold 0} for {@code flags} if no special * flags are desired. * * @param expressions * the array of expressions to compile into {@link Pattern} objects * @param flags * the Pattern flags to use, or {@bold 0} for no flags * @return the compiled regular expressions, in the same order as * {@code expressions}, or <em>null</em> if no expressions supplied * @throws PatternSyntaxException * If an expression's syntax is invalid */ public static Pattern[] patterns(final String[] expressions, int flags) { Pattern[] result = null; if ( expressions != null && expressions.length > 0 ) { result = new Pattern[expressions.length]; for ( int i = 0, len = expressions.length; i < len; i++ ) { result[i] = (flags == 0 ? Pattern.compile(expressions[i]) : Pattern.compile( expressions[i], flags)); } } return result; } /** * Create an array of expression strings from Pattern objects. If * {@code patterns} is <em>null</em> or empty, the result will be * <em>null</em>. * * @param patterns * the array of Pattern objects to convert to strings (may be * <em>null</em>) * @return the string expressions, in the same order as {@code patterns}, or * <em>null</em> if no patterns supplied */ public static String[] expressions(final Pattern[] patterns) { String[] results = null; if ( patterns != null && patterns.length > 0 ) { results = new String[patterns.length]; for ( int i = 0, len = patterns.length; i < len; i++ ) { results[i] = patterns[i].pattern(); } } return results; } /** * Test if a string matches any one of a list of patterns. The * {@code patterns} list will be tested one at a time, in array order. The * first result that matches will be returned. If no match is found, * <em>null</em> is returned. * * @param patterns * the patterns to test (may be <em>null</em>) * @param text * the string to test (may be <em>null</em>) * @return a {@link Matcher} that matches {@code text} or <em>null</em> if * no match was found */ public static Matcher matches(final Pattern[] patterns, String text) { if ( patterns == null || patterns.length < 0 || text == null ) { return null; } for ( Pattern pattern : patterns ) { Matcher m = pattern.matcher(text); if ( m.matches() ) { return m; } } return null; } }