/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.engine.util; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; /** * String manipulation utilities. * * @author Jerome Louvel */ public class StringUtils { /** * Represents an XML or HTML character entity reference. * * @author Thierry Boileau * */ private static class CharacterEntity { /** Character reference. */ private String name; /** Numeric character reference. */ private Integer numericValue; /** * Constructor. * * @param numericValue * The numeric value of the entity. * @param name * the name of the entity. */ public CharacterEntity(Integer numericValue, String name) { super(); this.numericValue = numericValue; this.name = name; } /** * Returns the name of the entity. * * @return The name of the entity. */ public String getName() { return name; } /** * Returns the numeric value of the entity. * * @return The numeric value of the entity. */ public Integer getNumericValue() { return numericValue; } } /** * Stores a list en entities and is able to return one given its numeric * value or name. * * @author Thierry Boileau * */ private static class CharacterEntitySolver { /** Map of names of entities according to their numeric value. */ private String[] toName; /** Map of numeric values of entities according to their name. */ private Map<String, Integer> toValue; /** * Constructor. */ public CharacterEntitySolver() { toName = new String[10000]; toValue = new HashMap<String, Integer>(); } /** * Adds an entity to solve. * * @param value * The numeric value of the entity. * @param name * The name of the entity. * @return The solver. */ public void add(Integer value, String name) { toName[value] = name; toValue.put(name, value); } /** * Returns the entity name according to its numeric value. * * @param value * The numeric value of the entity. * @return The entity name according to its numeric value. */ public String getName(int value) { return toName[value]; } /** * Returns the numeric value of an entity according to its name. * * @param name * The name of the entity. * @return The numeric value of an entity according to its name. */ public Integer getValue(String name) { return toValue.get(name); } } /** Entities defined for HTML 4.0. */ private static CharacterEntitySolver html40Entities; /** Entities defined in http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent. */ private static List<CharacterEntity> htmlLat1; /** Entities defined in http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent. */ private static List<CharacterEntity> htmlSpecial; /** Entities defined in http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent. */ private static List<CharacterEntity> htmlSymbol; /** Basic entities. */ private static List<CharacterEntity> xml10; static { xml10 = new ArrayList<CharacterEntity>(); xml10.add(new CharacterEntity(34, "quot")); xml10.add(new CharacterEntity(38, "amp")); xml10.add(new CharacterEntity(62, "gt")); xml10.add(new CharacterEntity(60, "lt")); htmlLat1 = new ArrayList<CharacterEntity>(); htmlLat1.add(new CharacterEntity(160, "nbsp")); htmlLat1.add(new CharacterEntity(161, "iexcl")); htmlLat1.add(new CharacterEntity(162, "cent")); htmlLat1.add(new CharacterEntity(163, "pound")); htmlLat1.add(new CharacterEntity(164, "curren")); htmlLat1.add(new CharacterEntity(165, "yen")); htmlLat1.add(new CharacterEntity(166, "brvbar")); htmlLat1.add(new CharacterEntity(167, "sect")); htmlLat1.add(new CharacterEntity(168, "uml")); htmlLat1.add(new CharacterEntity(169, "copy")); htmlLat1.add(new CharacterEntity(170, "ordf")); htmlLat1.add(new CharacterEntity(171, "laquo")); htmlLat1.add(new CharacterEntity(172, "not")); htmlLat1.add(new CharacterEntity(173, "shy")); htmlLat1.add(new CharacterEntity(174, "reg")); htmlLat1.add(new CharacterEntity(175, "macr")); htmlLat1.add(new CharacterEntity(176, "deg")); htmlLat1.add(new CharacterEntity(177, "plusmn")); htmlLat1.add(new CharacterEntity(178, "sup2")); htmlLat1.add(new CharacterEntity(179, "sup3")); htmlLat1.add(new CharacterEntity(180, "acute")); htmlLat1.add(new CharacterEntity(181, "micro")); htmlLat1.add(new CharacterEntity(182, "para")); htmlLat1.add(new CharacterEntity(183, "middot")); htmlLat1.add(new CharacterEntity(184, "cedil")); htmlLat1.add(new CharacterEntity(185, "sup1")); htmlLat1.add(new CharacterEntity(186, "ordm")); htmlLat1.add(new CharacterEntity(187, "raquo")); htmlLat1.add(new CharacterEntity(188, "frac14")); htmlLat1.add(new CharacterEntity(189, "frac12")); htmlLat1.add(new CharacterEntity(190, "frac34")); htmlLat1.add(new CharacterEntity(191, "iquest")); htmlLat1.add(new CharacterEntity(192, "Agrave")); htmlLat1.add(new CharacterEntity(193, "Aacute")); htmlLat1.add(new CharacterEntity(194, "Acirc")); htmlLat1.add(new CharacterEntity(195, "Atilde")); htmlLat1.add(new CharacterEntity(196, "Auml")); htmlLat1.add(new CharacterEntity(197, "Aring")); htmlLat1.add(new CharacterEntity(198, "AElig")); htmlLat1.add(new CharacterEntity(199, "Ccedil")); htmlLat1.add(new CharacterEntity(200, "Egrave")); htmlLat1.add(new CharacterEntity(201, "Eacute")); htmlLat1.add(new CharacterEntity(202, "Ecirc")); htmlLat1.add(new CharacterEntity(203, "Euml")); htmlLat1.add(new CharacterEntity(204, "Igrave")); htmlLat1.add(new CharacterEntity(205, "Iacute")); htmlLat1.add(new CharacterEntity(206, "Icirc")); htmlLat1.add(new CharacterEntity(207, "Iuml")); htmlLat1.add(new CharacterEntity(208, "ETH")); htmlLat1.add(new CharacterEntity(209, "Ntilde")); htmlLat1.add(new CharacterEntity(210, "Ograve")); htmlLat1.add(new CharacterEntity(211, "Oacute")); htmlLat1.add(new CharacterEntity(212, "Ocirc")); htmlLat1.add(new CharacterEntity(213, "Otilde")); htmlLat1.add(new CharacterEntity(214, "Ouml")); htmlLat1.add(new CharacterEntity(215, "times")); htmlLat1.add(new CharacterEntity(216, "Oslash")); htmlLat1.add(new CharacterEntity(217, "Ugrave")); htmlLat1.add(new CharacterEntity(218, "Uacute")); htmlLat1.add(new CharacterEntity(219, "Ucirc")); htmlLat1.add(new CharacterEntity(220, "Uuml")); htmlLat1.add(new CharacterEntity(221, "Yacute")); htmlLat1.add(new CharacterEntity(222, "THORN")); htmlLat1.add(new CharacterEntity(223, "szlig")); htmlLat1.add(new CharacterEntity(224, "agrave")); htmlLat1.add(new CharacterEntity(225, "aacute")); htmlLat1.add(new CharacterEntity(226, "acirc")); htmlLat1.add(new CharacterEntity(227, "atilde")); htmlLat1.add(new CharacterEntity(228, "auml")); htmlLat1.add(new CharacterEntity(229, "aring")); htmlLat1.add(new CharacterEntity(230, "aelig")); htmlLat1.add(new CharacterEntity(231, "ccedil")); htmlLat1.add(new CharacterEntity(232, "egrave")); htmlLat1.add(new CharacterEntity(233, "eacute")); htmlLat1.add(new CharacterEntity(234, "ecirc")); htmlLat1.add(new CharacterEntity(235, "euml")); htmlLat1.add(new CharacterEntity(236, "igrave")); htmlLat1.add(new CharacterEntity(237, "iacute")); htmlLat1.add(new CharacterEntity(238, "icirc")); htmlLat1.add(new CharacterEntity(239, "iuml")); htmlLat1.add(new CharacterEntity(240, "eth")); htmlLat1.add(new CharacterEntity(241, "ntilde")); htmlLat1.add(new CharacterEntity(242, "ograve")); htmlLat1.add(new CharacterEntity(243, "oacute")); htmlLat1.add(new CharacterEntity(244, "ocirc")); htmlLat1.add(new CharacterEntity(245, "otilde")); htmlLat1.add(new CharacterEntity(246, "ouml")); htmlLat1.add(new CharacterEntity(247, "divide")); htmlLat1.add(new CharacterEntity(248, "oslash")); htmlLat1.add(new CharacterEntity(249, "ugrave")); htmlLat1.add(new CharacterEntity(250, "uacute")); htmlLat1.add(new CharacterEntity(251, "ucirc")); htmlLat1.add(new CharacterEntity(252, "uuml")); htmlLat1.add(new CharacterEntity(253, "yacute")); htmlLat1.add(new CharacterEntity(254, "thorn")); htmlLat1.add(new CharacterEntity(255, "yuml")); htmlSymbol = new ArrayList<CharacterEntity>(); htmlSymbol.add(new CharacterEntity(402, "fnof")); htmlSymbol.add(new CharacterEntity(913, "Alpha")); htmlSymbol.add(new CharacterEntity(914, "Beta")); htmlSymbol.add(new CharacterEntity(915, "Gamma")); htmlSymbol.add(new CharacterEntity(916, "Delta")); htmlSymbol.add(new CharacterEntity(917, "Epsilon")); htmlSymbol.add(new CharacterEntity(918, "Zeta")); htmlSymbol.add(new CharacterEntity(919, "Eta")); htmlSymbol.add(new CharacterEntity(920, "Theta")); htmlSymbol.add(new CharacterEntity(921, "Iota")); htmlSymbol.add(new CharacterEntity(922, "Kappa")); htmlSymbol.add(new CharacterEntity(923, "Lambda")); htmlSymbol.add(new CharacterEntity(924, "Mu")); htmlSymbol.add(new CharacterEntity(925, "Nu")); htmlSymbol.add(new CharacterEntity(926, "Xi")); htmlSymbol.add(new CharacterEntity(927, "Omicron")); htmlSymbol.add(new CharacterEntity(928, "Pi")); htmlSymbol.add(new CharacterEntity(929, "Rho")); htmlSymbol.add(new CharacterEntity(931, "Sigma")); htmlSymbol.add(new CharacterEntity(932, "Tau")); htmlSymbol.add(new CharacterEntity(933, "Upsilon")); htmlSymbol.add(new CharacterEntity(934, "Phi")); htmlSymbol.add(new CharacterEntity(935, "Chi")); htmlSymbol.add(new CharacterEntity(936, "Psi")); htmlSymbol.add(new CharacterEntity(937, "Omega")); htmlSymbol.add(new CharacterEntity(945, "alpha")); htmlSymbol.add(new CharacterEntity(946, "beta")); htmlSymbol.add(new CharacterEntity(947, "gamma")); htmlSymbol.add(new CharacterEntity(948, "delta")); htmlSymbol.add(new CharacterEntity(949, "epsilon")); htmlSymbol.add(new CharacterEntity(950, "zeta")); htmlSymbol.add(new CharacterEntity(951, "eta")); htmlSymbol.add(new CharacterEntity(952, "theta")); htmlSymbol.add(new CharacterEntity(953, "iota")); htmlSymbol.add(new CharacterEntity(954, "kappa")); htmlSymbol.add(new CharacterEntity(955, "lambda")); htmlSymbol.add(new CharacterEntity(956, "mu")); htmlSymbol.add(new CharacterEntity(957, "nu")); htmlSymbol.add(new CharacterEntity(958, "xi")); htmlSymbol.add(new CharacterEntity(959, "omicron")); htmlSymbol.add(new CharacterEntity(960, "pi")); htmlSymbol.add(new CharacterEntity(961, "rho")); htmlSymbol.add(new CharacterEntity(962, "sigmaf")); htmlSymbol.add(new CharacterEntity(963, "sigma")); htmlSymbol.add(new CharacterEntity(964, "tau")); htmlSymbol.add(new CharacterEntity(965, "upsilon")); htmlSymbol.add(new CharacterEntity(966, "phi")); htmlSymbol.add(new CharacterEntity(967, "chi")); htmlSymbol.add(new CharacterEntity(968, "psi")); htmlSymbol.add(new CharacterEntity(969, "omega")); htmlSymbol.add(new CharacterEntity(977, "thetasym")); htmlSymbol.add(new CharacterEntity(978, "upsih")); htmlSymbol.add(new CharacterEntity(982, "piv")); htmlSymbol.add(new CharacterEntity(8230, "hellip")); htmlSymbol.add(new CharacterEntity(8242, "prime")); htmlSymbol.add(new CharacterEntity(8243, "Prime")); htmlSymbol.add(new CharacterEntity(8254, "oline")); htmlSymbol.add(new CharacterEntity(8260, "frasl")); htmlSymbol.add(new CharacterEntity(8465, "image")); htmlSymbol.add(new CharacterEntity(8472, "weierp")); htmlSymbol.add(new CharacterEntity(8476, "real")); htmlSymbol.add(new CharacterEntity(8482, "trade")); htmlSymbol.add(new CharacterEntity(8501, "alefsym")); htmlSymbol.add(new CharacterEntity(8592, "larr")); htmlSymbol.add(new CharacterEntity(8593, "uarr")); htmlSymbol.add(new CharacterEntity(8594, "rarr")); htmlSymbol.add(new CharacterEntity(8595, "darr")); htmlSymbol.add(new CharacterEntity(8596, "harr")); htmlSymbol.add(new CharacterEntity(8629, "crarr")); htmlSymbol.add(new CharacterEntity(8656, "lArr")); htmlSymbol.add(new CharacterEntity(8657, "uArr")); htmlSymbol.add(new CharacterEntity(8658, "rArr")); htmlSymbol.add(new CharacterEntity(8659, "dArr")); htmlSymbol.add(new CharacterEntity(8660, "hArr")); htmlSymbol.add(new CharacterEntity(8704, "forall")); htmlSymbol.add(new CharacterEntity(8706, "part")); htmlSymbol.add(new CharacterEntity(8707, "exist")); htmlSymbol.add(new CharacterEntity(8709, "empty")); htmlSymbol.add(new CharacterEntity(8711, "nabla")); htmlSymbol.add(new CharacterEntity(8712, "isin")); htmlSymbol.add(new CharacterEntity(8713, "notin")); htmlSymbol.add(new CharacterEntity(8715, "ni")); htmlSymbol.add(new CharacterEntity(8719, "prod")); htmlSymbol.add(new CharacterEntity(8721, "sum")); htmlSymbol.add(new CharacterEntity(8722, "minus")); htmlSymbol.add(new CharacterEntity(8727, "lowast")); htmlSymbol.add(new CharacterEntity(8730, "radic")); htmlSymbol.add(new CharacterEntity(8733, "prop")); htmlSymbol.add(new CharacterEntity(8734, "infin")); htmlSymbol.add(new CharacterEntity(8736, "ang")); htmlSymbol.add(new CharacterEntity(8743, "and")); htmlSymbol.add(new CharacterEntity(8744, "or")); htmlSymbol.add(new CharacterEntity(8745, "cap")); htmlSymbol.add(new CharacterEntity(8746, "cup")); htmlSymbol.add(new CharacterEntity(8747, "int")); htmlSymbol.add(new CharacterEntity(8756, "there4")); htmlSymbol.add(new CharacterEntity(8764, "sim")); htmlSymbol.add(new CharacterEntity(8773, "cong")); htmlSymbol.add(new CharacterEntity(8776, "asymp")); htmlSymbol.add(new CharacterEntity(8800, "ne")); htmlSymbol.add(new CharacterEntity(8801, "equiv")); htmlSymbol.add(new CharacterEntity(8804, "le")); htmlSymbol.add(new CharacterEntity(8805, "ge")); htmlSymbol.add(new CharacterEntity(8834, "sub")); htmlSymbol.add(new CharacterEntity(8835, "sup")); htmlSymbol.add(new CharacterEntity(8836, "nsub")); htmlSymbol.add(new CharacterEntity(8838, "sube")); htmlSymbol.add(new CharacterEntity(8839, "supe")); htmlSymbol.add(new CharacterEntity(8853, "oplus")); htmlSymbol.add(new CharacterEntity(8855, "otimes")); htmlSymbol.add(new CharacterEntity(8869, "perp")); htmlSymbol.add(new CharacterEntity(8901, "sdot")); htmlSymbol.add(new CharacterEntity(8968, "lceil")); htmlSymbol.add(new CharacterEntity(8969, "rceil")); htmlSymbol.add(new CharacterEntity(8970, "lfloor")); htmlSymbol.add(new CharacterEntity(8971, "rfloor")); htmlSymbol.add(new CharacterEntity(9001, "lang")); htmlSymbol.add(new CharacterEntity(9002, "rang")); htmlSymbol.add(new CharacterEntity(9674, "loz")); htmlSymbol.add(new CharacterEntity(9824, "spades")); htmlSymbol.add(new CharacterEntity(9827, "clubs")); htmlSymbol.add(new CharacterEntity(9829, "hearts")); htmlSymbol.add(new CharacterEntity(9830, "diams")); htmlSpecial = new ArrayList<CharacterEntity>(); htmlSpecial.add(new CharacterEntity(34, "quot")); htmlSpecial.add(new CharacterEntity(38, "amp")); htmlSpecial.add(new CharacterEntity(39, "apos")); htmlSpecial.add(new CharacterEntity(60, "lt")); htmlSpecial.add(new CharacterEntity(62, "gt")); htmlSpecial.add(new CharacterEntity(338, "OElig")); htmlSpecial.add(new CharacterEntity(339, "oelig")); htmlSpecial.add(new CharacterEntity(352, "Scaron")); htmlSpecial.add(new CharacterEntity(353, "scaron")); htmlSpecial.add(new CharacterEntity(376, "Yuml")); htmlSpecial.add(new CharacterEntity(710, "circ")); htmlSpecial.add(new CharacterEntity(732, "tilde")); htmlSpecial.add(new CharacterEntity(8194, "ensp")); htmlSpecial.add(new CharacterEntity(8195, "emsp")); htmlSpecial.add(new CharacterEntity(8201, "thinsp")); htmlSpecial.add(new CharacterEntity(8204, "zwnj")); htmlSpecial.add(new CharacterEntity(8205, "zwj")); htmlSpecial.add(new CharacterEntity(8206, "lrm")); htmlSpecial.add(new CharacterEntity(8207, "rlm")); htmlSpecial.add(new CharacterEntity(8211, "ndash")); htmlSpecial.add(new CharacterEntity(8212, "mdash")); htmlSpecial.add(new CharacterEntity(8216, "lsquo")); htmlSpecial.add(new CharacterEntity(8217, "rsquo")); htmlSpecial.add(new CharacterEntity(8218, "sbquo")); htmlSpecial.add(new CharacterEntity(8220, "ldquo")); htmlSpecial.add(new CharacterEntity(8221, "rdquo")); htmlSpecial.add(new CharacterEntity(8222, "bdquo")); htmlSpecial.add(new CharacterEntity(8224, "dagger")); htmlSpecial.add(new CharacterEntity(8225, "Dagger")); htmlSpecial.add(new CharacterEntity(8226, "bull")); htmlSpecial.add(new CharacterEntity(8240, "permil")); htmlSpecial.add(new CharacterEntity(8249, "lsaquo")); htmlSpecial.add(new CharacterEntity(8250, "rsaquo")); htmlSpecial.add(new CharacterEntity(8364, "euro")); List<CharacterEntity> list = new ArrayList<CharacterEntity>(); list.addAll(xml10); list.addAll(htmlLat1); list.addAll(htmlSymbol); list.addAll(htmlSpecial); html40Entities = new CharacterEntitySolver(); for (CharacterEntity entity : xml10) { html40Entities.add(entity.getNumericValue(), entity.getName()); } for (CharacterEntity entity : htmlLat1) { html40Entities.add(entity.getNumericValue(), entity.getName()); } for (CharacterEntity entity : htmlSymbol) { html40Entities.add(entity.getNumericValue(), entity.getName()); } for (CharacterEntity entity : htmlSpecial) { html40Entities.add(entity.getNumericValue(), entity.getName()); } } /** * Returns the string with the first character capitalized. * * * @param string * a string reference to check * @return the string with the first character capitalized. */ public static String firstLower(String string) { if (!isNullOrEmpty(string)) { return string.substring(0, 1).toLowerCase() + string.substring(1); } return string; } /** * Returns the string with the first character capitalized. * * * @param string * a string reference to check * @return the string with the first character capitalized. */ public static String firstUpper(String string) { if (!isNullOrEmpty(string)) { return string.substring(0, 1).toUpperCase() + string.substring(1); } return string; } // [ifndef gwt] method /** * Encodes the given String into a sequence of bytes using the Ascii * character set. * * @param string * The string to encode. * @return The String encoded with the Ascii character set as an array of * bytes. */ public static byte[] getAsciiBytes(String string) { if (string != null) { try { return string.getBytes("US-ASCII"); } catch (Exception e) { // Should not happen. return null; } } return null; } // [ifndef gwt] method /** * Encodes the given String into a sequence of bytes using the Latin1 * character set. * * @param string * The string to encode. * @return The String encoded with the Latin1 character set as an array of * bytes. */ public static byte[] getLatin1Bytes(String string) { if (string != null) { try { return string.getBytes("ISO-8859-1"); } catch (Exception e) { // Should not happen. return null; } } return null; } /** * Returns the given {@link String} according to the HTML 4.0 encoding * rules. * * @param str * The {@link String} to encode. * @return The converted {@link String} according to the HTML 4.0 encoding * rules. */ public static String htmlEscape(String str) { if (str == null) { return null; } int len = str.length(); StringBuilder sb = new StringBuilder((int) (len * 1.5)); for (int i = 0; i < len; i++) { char c = str.charAt(i); String entityName = html40Entities.getName(c); if (entityName == null) { if (c > 127) { // Escape non ASCII characters. sb.append("&#").append(Integer.toString(c, 10)).append(';'); } else { // ASCII characters are not escaped. sb.append(c); } } else { sb.append('&').append(entityName).append(';'); } } return sb.toString(); } /** * Returns the given {@link String} decoded according to the HTML 4.0 * decoding rules. * * @param str * The {@link String} to decode. * @return The given {@link String} decoded according to the HTML 4.0 * decoding rules. */ public static String htmlUnescape(String str) { if (str == null) { return null; } int len = str.length(); StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { char c = str.charAt(i); if (c == '&') { int nextIndex = i + 1; int semicolonIndex = -1; int ampersandIndex = -1; boolean stop = false; for (int j = nextIndex; !stop && j < len; j++) { char ch = str.charAt(j); if (';' == ch) { semicolonIndex = j; stop = true; } else if ('&' == ch) { ampersandIndex = j; stop = true; } } if (semicolonIndex != -1) { // Entity found if (nextIndex != semicolonIndex) { int entityValue = -1; String entityName = str.substring(nextIndex, semicolonIndex); if (entityName.charAt(0) == '#') { // Numeric value if (entityName.length() > 1) { char hexChar = entityName.charAt(1); try { if (hexChar == 'X') { entityValue = Integer.parseInt( entityName.substring(2), 16); } else if (hexChar == 'x') { entityValue = Integer.parseInt( entityName.substring(2), 16); } else { entityValue = Integer.parseInt( entityName.substring(1), 10); } if (!Character .isValidCodePoint(entityValue)) { // Invalid Unicode character entityValue = -1; } } catch (NumberFormatException e) { entityValue = -1; } } } else { Integer val = html40Entities.getValue(entityName); if (val != null) { entityValue = val.intValue(); } } if (entityValue == -1) { sb.append('&').append(entityName).append(';'); } else { sb.append((char) entityValue); } } else { sb.append("&;"); } i = semicolonIndex; } else if (stop) { // found a "&" character sb.append(str, i, ampersandIndex).append('&'); i = ampersandIndex; } else { // End of the string reached, no more entities to parse. sb.append(str, i, len); i = len; } } else { sb.append(c); } } return sb.toString(); } /** * Returns {@code true} if the given string is null or is the empty string. * * <p> * Consider normalizing your string references with {@link #nullToEmpty}. If * you do, you can use {@link String#isEmpty()} instead of this method, and * you won't need special null-safe forms of methods like * {@link String#toUpperCase} either. * * @param string * a string reference to check * @return {@code true} if the string is null or is the empty string */ public static boolean isNullOrEmpty(String string) { return string == null || string.isEmpty(); } /** * Returns the given string if it is non-null; the empty string otherwise. * * @param string * the string to test and possibly return * @return {@code string} itself if it is non-null; {@code ""} if it is null */ public static String nullToEmpty(String string) { return (string == null) ? "" : string; } // [ifndef gwt] method /** * Returns an list of trimmed token splitted with the split character ",". * * @param stringToSplit * The String to split. * @return List of tokens. */ public static List<String> splitAndTrim(String stringToSplit) { return splitAndTrim(stringToSplit, ","); } // [ifndef gwt] method /** * Returns an list of trimmed token splitted with the split character. * * @param stringToSplit * The String to split. * @param splitCharacter * The split Character. * @return List of tokens. */ public static List<String> splitAndTrim(String stringToSplit, String splitCharacter) { List<String> list = new ArrayList<>(); // StringTokenizer is 3 times more performant than String#split. StringTokenizer st = new StringTokenizer(stringToSplit, splitCharacter); while (st.hasMoreTokens()) { list.add(st.nextToken().trim()); } return list; } /** * Strips a delimiter character from both ends of the source string. * * @param source * The source string to strip. * @param delimiter * The character to remove. * @return The stripped string. */ public static String strip(String source, char delimiter) { return strip(source, delimiter, true, true); } /** * Strips a delimiter character from a source string. * * @param source * The source string to strip. * @param delimiter * The character to remove. * @param start * Indicates if start of source should be stripped. * @param end * Indicates if end of source should be stripped. * @return The stripped source string. */ public static String strip(String source, char delimiter, boolean start, boolean end) { int beginIndex = 0; int endIndex = source.length(); boolean stripping = true; // Strip beginning while (stripping && (beginIndex < endIndex)) { if (source.charAt(beginIndex) == delimiter) { beginIndex++; } else { stripping = false; } } // Strip end stripping = true; while (stripping && (beginIndex < endIndex - 1)) { if (source.charAt(endIndex - 1) == delimiter) { endIndex--; } else { stripping = false; } } return source.substring(beginIndex, endIndex); } /** * Private constructor to ensure that the class acts as a true utility class * i.e. it isn't instantiable and extensible. */ private StringUtils() { } }