package com.cloudhopper.commons.util; /* * #%L * ch-commons-util * %% * Copyright (C) 2012 Cloudhopper by Twitter * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.io.IOException; import java.io.InputStream; import java.util.Locale; import java.util.Properties; import java.util.StringTokenizer; /** * A set of String utilities. * * @author joelauer (twitter: @jjlauer or <a href="http://twitter.com/jjlauer" target=window>http://twitter.com/jjlauer</a>) */ public class StringUtil { private static final String PRINTABLE = ": ~`!@#$%^&*()-_+=/\\,.[]{}|?<>\"'"; private static final String SAFE = ":~!@#$%^&*()-_+=/\\,.[]{}|?<>"; // (gt, lt, quot, amp, apos) and then newline, carriage return private static final String[][] XML_CHARS = { { "&", "&"}, { "<", "<"}, { ">", ">"}, { "\"", """}, { "'", "'"}, { "\n", " "}, { "\r", " "}, }; /** * Searches the string for occurrences of the pattern $ENV{key} and * attempts to replace this pattern with a value from the System environment * obtained using the 'key'. For example, including "$ENV{USERNAME}" in * a string and calling this method would then attempt to replace the entire * pattern with the value of the environment variable "USERNAME". The System * environment is obtained in Java with a call to System.getenv(). An environment variable is typically * defined in the Linux shell or Windows property tabs. NOTE: A Java System * property is not the same as an environment variable. * @param string0 The string to perform substitution on such as "Hello $ENV{USERNAME}". * This string may be null, empty, or contain one or more substitutions. * @return A string with all occurrences of keys substituted with their * values obtained from the System environment. Can be null if the * original string was null. * @throws SubstitutionException Thrown if a starting string was found, but the * ending string was not. Also, thrown if a key value was empty such * as using "$ENV{}". Finally, thrown if the property key was not * found in the properties object (could not be replaced). * @see #substituteWithProperties(java.lang.String, java.lang.String, java.lang.String, java.util.Properties) */ public static String substituteWithEnvironment(String string0) throws SubstitutionException { // turn environment into properties Properties envProps = new Properties(); // add all system environment vars to the properties envProps.putAll(System.getenv()); // delegate to other method using the default syntax $ENV{<key>} return substituteWithProperties(string0, "$ENV{", "}", envProps); } /** * Searches string for occurrences of a pattern, extracts out a key name * between the startStr and endStr tokens, then attempts to replace the * property value into the string. This method is useful for merging * property values into configuration strings/settings. For examle, the * system environment Map could be converted into a Properties object then * have its values merged into a String so that users can access environment * variables. * @param string0 The string to perform substitution on such as "Hello $ENV{TEST}". * This string may be null, empty, or contain one or more substitutions. * @param startStr The string that marks the start of a replacement key such * as "$ENV{" if the final search pattern you wanted was "$ENV{<key>}". * @param endStr The string that marks the end of a replacement key such * as "}" if the final search pattern you wanted was "$ENV{<key>}". * @param properties The property keys and associated values to use for * replacement. * @return A string with all occurrences of keys substituted with their * values obtained from the properties object. Can be null if the * original string was null. * @throws SubstitutionException Thrown if a starting string was found, but the * ending string was not. Also, thrown if a key value was empty such * as using "$ENV{}". Finally, thrown if the property key was not * found in the properties object (could not be replaced). * @see #substituteWithEnvironment(java.lang.String) */ public static String substituteWithProperties(String string0, String startStr, String endStr, Properties properties) throws SubstitutionException { // a null source string will always return the same -- a null result if (string0 == null) { return null; } // create a builder for the resulting string StringBuilder result = new StringBuilder(string0.length()); // attempt to find the first occurrence of the starting string int end = -1; int pos = string0.indexOf(startStr); // keep looping while we keep finding more occurrences while (pos >= 0) { // is there string data before the position that we should append to the result? if (pos > end+1) { result.append(string0.substring(end+endStr.length(), pos)); } // search for endStr starting from the end of the startStr end = string0.indexOf(endStr, pos+startStr.length()); // was the end found? if (end < 0) { throw new SubstitutionException("End of substitution pattern '" + endStr + "' not found [@position=" + pos + "]"); } // extract the part in the middle of the start and end strings String key = string0.substring(pos+startStr.length(), end); // NOTE: don't trim the key, whitespace technically matters... // was there anything left? if (key == null || key.equals("")) { throw new SubstitutionException("Property key was empty in string with an occurrence of '" + startStr + endStr + "' [@position=" + pos + "]"); } // attempt to get this property String value = properties.getProperty(key); // was the property found if (value == null) { throw new SubstitutionException("A property value for '" + startStr + key + endStr + "' was not found (property missing?)"); } // append this value to our result result.append(value); // find next occurrence after last end pos = string0.indexOf(startStr, end+endStr.length()); } // is there any string data we missed in the loop above? if (end+endStr.length() < string0.length()) { // append the remaining part of the string result.append(string0.substring(end+endStr.length())); } return result.toString(); } /** * Returns true if the String is considered a "safe" string where only specific * characters are allowed to be used. Useful for checking passwords or other * information you don't want a user to be able to type just anything in. * This method does not allow any whitespace characters, newlines, carriage returns. * Primarily allows [a-z] [A-Z] [0-9] and a few other useful ASCII characters * such as ":~!@#$%^*()-_+=/\\,.[]{}|?<>" (but not the quote chars) */ public static boolean isSafeString(String string0) { for (int i = 0; i < string0.length(); i++) { if (!isSafeChar(string0.charAt(i))) { return false; } } return true; } /** * Returns true if the char is considered a "safe" char. Please see * documentation for isSafeString(). * @see #isSafeString(java.lang.String) */ public static boolean isSafeChar(char ch) { if (ch >= 'a' && ch <= 'z') return true; if (ch >= 'A' && ch <= 'Z') return true; if (ch >= '0' && ch <= '9') return true; // loop thru our PRINTABLE string for (int i = 0; i < SAFE.length(); i++) { if (ch == SAFE.charAt(i)) return true; } return false; } /** * Safely capitalizes a string by converting the first character to upper * case. Handles null, empty, and strings of length of 1 or greater. For * example, this will convert "joe" to "Joe". If the string is null, this * will return null. If the string is empty such as "", then it'll just * return an empty string such as "". * @param string0 The string to capitalize * @return A new string with the first character converted to upper case */ static public String capitalize(String string0) { if (string0 == null) { return null; } int length = string0.length(); // if empty string, just return it if (length == 0) { return string0; } else if (length == 1) { return string0.toUpperCase(); } else { StringBuilder buf = new StringBuilder(length); buf.append(string0.substring(0, 1).toUpperCase()); buf.append(string0.substring(1)); return buf.toString(); } } /** * Safely uncapitalizes a string by converting the first character to lower * case. Handles null, empty, and strings of length of 1 or greater. For * example, this will convert "Joe" to "joe". If the string is null, this * will return null. If the string is empty such as "", then it'll just * return an empty string such as "". * @param string0 The string to uncapitalize * @return A new string with the first character converted to lower case */ static public String uncapitalize(String string0) { if (string0 == null) { return null; } int length = string0.length(); // if empty string, just return it if (length == 0) { return string0; } else if (length == 1) { return string0.toLowerCase(); } else { StringBuilder buf = new StringBuilder(length); buf.append(string0.substring(0, 1).toLowerCase()); buf.append(string0.substring(1)); return buf.toString(); } } /** * Checks if the targetString is contained within the array of strings. This * method will return true if a "null" is contained in the array and the * targetString is also null. * @param strings The array of strings to search. * @param targetString The string to search for * @return True if the string is contained within, otherwise false. Also * returns false if the strings array is null. */ static public boolean contains(String[] strings, String targetString) { return (indexOf(strings, targetString) != -1); } /** * Finds the first occurrence of the targetString in the array of strings. * Returns -1 if an occurrence wasn't found. This * method will return true if a "null" is contained in the array and the * targetString is also null. * @param strings The array of strings to search. * @param targetString The string to search for * @return The index of the first occurrence, or -1 if not found. If strings * array is null, will return -1; */ static public int indexOf(String[] strings, String targetString) { if (strings == null) return -1; for (int i = 0; i < strings.length; i++) { if (strings[i] == null) { if (targetString == null) { return i; } } else { if (targetString != null) { if (strings[i].equals(targetString)) { return i; } } } } return -1; } /** * If present, this method will strip off the leading and trailing " * character in the string parameter. For example, "10958" will * becomes just 10958. */ static public String stripQuotes(String string0) { // if an empty string, return it if (string0.length() == 0) { return string0; } // if the first and last characters are quotes, just do 1 substring if (string0.length() > 1 && string0.charAt(0) == '"' && string0.charAt(string0.length() - 1) == '"') { return string0.substring(1, string0.length() - 1); } else if (string0.charAt(0) == '"') { string0 = string0.substring(1); } else if (string0.charAt(string0.length() - 1) == '"') { string0 = string0.substring(0, string0.length() - 1); } return string0; } /** * Checks if a string contains only digits. * @return True if the string0 only contains digits, or false otherwise. */ static public boolean containsOnlyDigits(String string0) { // are they all digits? for (int i = 0; i < string0.length(); i++) { if (!Character.isDigit(string0.charAt(i))) { return false; } } return true; } /** * Splits a string around matches of the given delimiter character. * * Where applicable, this method can be used as a substitute for * <code>String.split(String regex)</code>, which is not available * on a JSR169/Java ME platform. * * @param str the string to be split * @param delim the delimiter * @throws NullPointerException if str is null */ static public String[] split(String str, char delim) { if (str == null) { throw new NullPointerException("str can't be null"); } // Note the javadoc on StringTokenizer: // StringTokenizer is a legacy class that is retained for // compatibility reasons although its use is discouraged in // new code. // In other words, if StringTokenizer is ever removed from the JDK, // we need to have a look at String.split() (or java.util.regex) // if it is supported on a JSR169/Java ME platform by then. StringTokenizer st = new StringTokenizer(str, String.valueOf(delim)); int n = st.countTokens(); String[] s = new String[n]; for (int i = 0; i < n; i++) { s[i] = st.nextToken(); } return s; } /** * Used to print out a string for error messages, * chops is off at 60 chars for historical reasons. */ public final static String formatForPrint(String input) { if (input.length() > 60) { StringBuffer tmp = new StringBuffer(input.substring(0, 60)); tmp.append("&"); input = tmp.toString(); } return input; } /** * A method that receive an array of Objects and return a * String array representation of that array. */ public static String[] toStringArray(Object[] objArray) { int idx; int len = objArray.length; String[] strArray = new String[len]; for (idx = 0; idx < len; idx++) { strArray[idx] = objArray[idx].toString(); } return strArray; } /** Get 7-bit ASCII character array from input String. The lower 7 bits of each character in the input string is assumed to be the ASCII character value. Hexadecimal - Character | 00 NUL| 01 SOH| 02 STX| 03 ETX| 04 EOT| 05 ENQ| 06 ACK| 07 BEL| | 08 BS | 09 HT | 0A NL | 0B VT | 0C NP | 0D CR | 0E SO | 0F SI | | 10 DLE| 11 DC1| 12 DC2| 13 DC3| 14 DC4| 15 NAK| 16 SYN| 17 ETB| | 18 CAN| 19 EM | 1A SUB| 1B ESC| 1C FS | 1D GS | 1E RS | 1F US | | 20 SP | 21 ! | 22 " | 23 # | 24 $ | 25 % | 26 & | 27 ' | | 28 ( | 29 ) | 2A * | 2B + | 2C , | 2D - | 2E . | 2F / | | 30 0 | 31 1 | 32 2 | 33 3 | 34 4 | 35 5 | 36 6 | 37 7 | | 38 8 | 39 9 | 3A : | 3B ; | 3C < | 3D = | 3E > | 3F ? | | 40 @ | 41 A | 42 B | 43 C | 44 D | 45 E | 46 F | 47 G | | 48 H | 49 I | 4A J | 4B K | 4C L | 4D M | 4E N | 4F O | | 50 P | 51 Q | 52 R | 53 S | 54 T | 55 U | 56 V | 57 W | | 58 X | 59 Y | 5A Z | 5B [ | 5C \ | 5D ] | 5E ^ | 5F _ | | 60 ` | 61 a | 62 b | 63 c | 64 d | 65 e | 66 f | 67 g | | 68 h | 69 i | 6A j | 6B k | 6C l | 6D m | 6E n | 6F o | | 70 p | 71 q | 72 r | 73 s | 74 t | 75 u | 76 v | 77 w | | 78 x | 79 y | 7A z | 7B { | 7C | | 7D } | 7E ~ | 7F DEL| */ public static byte[] getAsciiBytes(String input) { char[] c = input.toCharArray(); byte[] b = new byte[c.length]; for (int i = 0; i < c.length; i++) { b[i] = (byte) (c[i] & 0x007F); } return b; } public static String getAsciiString(byte[] input) { StringBuffer buf = new StringBuffer(input.length); for (byte b : input) { buf.append((char) b); } return buf.toString(); } /** * Trim off trailing blanks but not leading blanks * @param str * @return The input with trailing blanks stipped off */ public static String trimTrailing(String str) { if (str == null) { return null; } int len = str.length(); for (; len > 0; len--) { if (!Character.isWhitespace(str.charAt(len - 1))) { break; } } return str.substring(0, len); } /** Truncate a String to the given length with no warnings or error raised if it is bigger. @param value String to be truncated @param length Maximum length of string @return Returns value if value is null or value.length() is less or equal to than length, otherwise a String representing value truncated to length. */ public static String truncate(String value, int length) { if (value != null && value.length() > length) { value = value.substring(0, length); } return value; } /** * Return a slice (substring) of the passed in value, optionally trimmed. * WARNING - endOffset is inclusive for historical reasons, unlike * String.substring() which has an exclusive ending offset. * @param value Value to slice, must be non-null. * @param beginOffset Inclusive start character * @param endOffset Inclusive end character * @param trim To trim or not to trim * @return Sliceed value. */ public static String slice(String value, int beginOffset, int endOffset, boolean trim) { String retval = value.substring(beginOffset, endOffset + 1); if (trim) { retval = retval.trim(); } return retval; } public static char[] HEX_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * @deprecated Please use new utility class HexUtil * @see HexUtil#toHexString(byte[]) */ @Deprecated public static String toHexString(byte[] bytes) { return HexUtil.toHexString(bytes); } /** * @deprecated Please use new utility class HexUtil * @see HexUtil#toHexString(byte[], int, int) */ @Deprecated public static String toHexString(byte[] bytes, int offset, int length) { return HexUtil.toHexString(bytes, offset, length); } /** * @deprecated Please use new utility class HexUtil * @see HexUtil#toByteArray(java.lang.CharSequence, int, int) */ @Deprecated public static byte[] toHexByte(String hexString, int offset, int length) { return HexUtil.toByteArray(hexString, offset, length); } /** * Converts from a hex string like "FF" to a byte[]. * @param string0 The string containing the hex-encoded data. * @return * @deprecated Please use new utility class HexUtil * @see HexUtil#toByteArray(java.lang.CharSequence) */ @Deprecated public static byte[] fromHexString(String hexString) { return HexUtil.toByteArray(hexString); } /** * Convert a hexidecimal string generated by toHexString() back into a byte array. * @param s String to convert * @param offset starting character (zero based) to convert. * @param length number of characters to convert. * @return the converted byte array. Returns null if the length is not a multiple of 2. * @deprecated Please use new utility class HexUtil * @see HexUtil#toByteArray(java.lang.CharSequence, int, int) */ @Deprecated public static byte[] fromHexString(String hexString, int offset, int length) { return HexUtil.toByteArray(hexString, offset, length); } /** * Return true if the character is printable in ASCII. Not using * Character.isLetterOrDigit(); applies to all unicode ranges. */ public static boolean isPrintableChar(char ch) { if (ch >= 'a' && ch <= 'z') { return true; } if (ch >= 'A' && ch <= 'Z') { return true; } if (ch >= '0' && ch <= '9') { return true; } // loop thru our PRINTABLE string for (int i = 0; i < PRINTABLE.length(); i++) { if (ch == PRINTABLE.charAt(i)) { return true; } } return false; } /** Convert a byte array to a human-readable String for debugging purposes. */ public static String hexDump(String prefix, byte[] data) { byte byte_value; StringBuffer str = new StringBuffer(data.length * 3); str.append(prefix); for (int i = 0; i < data.length; i += 16) { // dump the header: 00000000: String offset = Integer.toHexString(i); // "0" left pad offset field so it is always 8 char's long. str.append(" "); for (int offlen = offset.length(); offlen < 8; offlen++) { str.append("0"); } str.append(offset); str.append(":"); // dump hex version of 16 bytes per line. for (int j = 0; (j < 16) && ((i + j) < data.length); j++) { byte_value = data[i + j]; // add spaces between every 2 bytes. if ((j % 2) == 0) { str.append(" "); } // dump a single byte. byte high_nibble = (byte) ((byte_value & 0xf0) >>> 4); byte low_nibble = (byte) (byte_value & 0x0f); str.append(HEX_TABLE[high_nibble]); str.append(HEX_TABLE[low_nibble]); } // IF THIS IS THE LAST LINE OF HEX, THEN ADD THIS if (i + 16 > data.length) { // for debugging purposes, I want the last bytes always padded // over so that the ascii portion is correctly positioned int last_row_byte_count = data.length % 16; int num_bytes_short = 16 - last_row_byte_count; // number of spaces to add = (num bytes remaining * 2 spaces per byte) + (7 - (num bytes % 2)) int num_spaces = (num_bytes_short * 2) + (7 - (last_row_byte_count / 2)); for (int v = 0; v < num_spaces; v++) { str.append(" "); } } // dump ascii version of 16 bytes str.append(" "); for (int j = 0; (j < 16) && ((i + j) < data.length); j++) { char char_value = (char) data[i + j]; // RESOLVE (really want isAscii() or isPrintable()) //if (Character.isLetterOrDigit(char_value)) if (isPrintableChar(char_value)) { str.append(String.valueOf(char_value)); } else { str.append("."); } } // new line str.append("\n"); } // always trim off the last newline str.deleteCharAt(str.length() - 1); return (str.toString()); } // The functions below are used for uppercasing SQL in a consistent manner. // Derby will uppercase Turkish to the English locale to avoid i // uppercasing to an uppercase dotted i. In future versions, all // casing will be done in English. The result will be that we will get // only the 1:1 mappings in // http://www.unicode.org/Public/3.0-Update1/UnicodeData-3.0.1.txt // and avoid the 1:n mappings in //http://www.unicode.org/Public/3.0-Update1/SpecialCasing-3.txt // // Any SQL casing should use these functions /** Convert string to uppercase * Always use the java.util.ENGLISH locale * @param s string to uppercase * @return uppercased string */ public static String SQLToUpperCase(String s) { return s.toUpperCase(Locale.ENGLISH); } /** Compares two strings * Strings will be uppercased in english and compared * equivalent to s1.equalsIgnoreCase(s2) * throws NPE if s1 is null * * @param s1 first string to compare * @param s2 second string to compare * * @return true if the two upppercased ENGLISH values are equal * return false if s2 is null */ public static boolean SQLEqualsIgnoreCase(String s1, String s2) { if (s2 == null) { return false; } else { return SQLToUpperCase(s1).equals(SQLToUpperCase(s2)); } } /** * Normalize a SQL identifer, up-casing if <regular identifer>, * and handling of <delimited identifer> (SQL 2003, section 5.2). * The normal form is used internally in Derby. * * @param id syntacically correct SQL identifier */ public static String normalizeSQLIdentifier(String id) { if (id.length() == 0) { return id; } if (id.charAt(0) == '"' && id.length() >= 3 && id.charAt(id.length() - 1) == '"') { // assume syntax is OK, thats is, any quotes inside are doubled: return StringUtil.compressQuotes( id.substring(1, id.length() - 1), "\"\""); } else { return StringUtil.SQLToUpperCase(id); } } /** * Compress 2 adjacent (single or double) quotes into a single (s or d) * quote when found in the middle of a String. * * NOTE: """" or '''' will be compressed into "" or ''. * This function assumes that the leading and trailing quote from a * string or delimited identifier have already been removed. * @param source string to be compressed * @param quotes string containing two single or double quotes. * @return String where quotes have been compressed */ public static String compressQuotes(String source, String quotes) { String result = source; int index; /* Find the first occurrence of adjacent quotes. */ index = result.indexOf(quotes); /* Replace each occurrence with a single quote and begin the * search for the next occurrence from where we left off. */ while (index != -1) { result = result.substring(0, index + 1) + result.substring(index + 2); index = result.indexOf(quotes, index + 1); } return result; } /** * Quote a string so that it can be used as an identifier or a string * literal in SQL statements. Identifiers are surrounded by double quotes * and string literals are surrounded by single quotes. If the string * contains quote characters, they are escaped. * * @param source the string to quote * @param quote the character to quote the string with (' or ") * @return a string quoted with the specified quote character * @see #quoteStringLiteral(String) * @see IdUtil#normalToDelimited(String) */ static String quoteString(String source, char quote) { // Normally, the quoted string is two characters longer than the source // string (because of start quote and end quote). StringBuffer quoted = new StringBuffer(source.length() + 2); quoted.append(quote); for (int i = 0; i < source.length(); i++) { char c = source.charAt(i); // if the character is a quote, escape it with an extra quote if (c == quote) quoted.append(quote); quoted.append(c); } quoted.append(quote); return quoted.toString(); } /** * Quote a string so that it can be used as a string literal in an * SQL statement. * * @param string the string to quote * @return the string surrounded by single quotes and with proper escaping * of any single quotes inside the string */ public static String quoteStringLiteral(String string) { return quoteString(string, '\''); } /** * Turn an array of ints into a printable string. Returns what's returned * in Java 5 by java.util.Arrays.toString(int[]). */ public static String stringify(int[] raw) { if (raw == null) { return "null"; } StringBuffer buffer = new StringBuffer(); int count = raw.length; buffer.append("[ "); for (int i = 0; i < count; i++) { if (i > 0) { buffer.append(", "); } buffer.append(raw[i]); } buffer.append(" ]"); return buffer.toString(); } /** * Checks if the string is an empty value which is true if the string is * null or if the string represents an empty string of "". Please note that * a string with just a space " " would not be considered empty. * @param string0 The string to check * @return True if null or "", otherwise false. */ public static boolean isEmpty(String string0) { if (string0 == null || string0.length() == 0) { return true; } else { return false; } } public static boolean isEqual(String string0, String string1) { return isEqual(string0, string1, true); } /** * Returns the value from calling "toString()" on the object, but is a safe * version that gracefully handles NULL objects by returning a String of "". * @param obj The object to call toString() on. Safely handles a null object. * @return The value from obj.toString() or "" if the object is null. * @see #toStringWithNullAsNull(java.lang.Object) */ static public String toStringWithNullAsEmpty(Object obj) { if (obj == null) { return ""; } else { return obj.toString(); } } /** * Returns the value from calling "toString()" on the object, but is a safe * version that gracefully handles NULL objects by returning a String of "<NULL>". * @param obj The object to call toString() on. Safely handles a null object. * @return The value from obj.toString() or "<NULL>" if the object is null. * @see #toStringWithNullAsEmpty(java.lang.Object) */ static public String toStringWithNullAsReplaced(Object obj) { if (obj == null) { return "<NULL>"; } else { return obj.toString(); } } /** * Returns the value from calling "toString()" on the object, but is a safe * version that gracefully handles NULL objects by returning null (rather * than causing a NullPointerException). * @param obj The object to call toString() on. Safely handles a null object. * @return The value from obj.toString() or null if the object is null. * @see #toStringWithNullAsEmpty(java.lang.Object) */ static public String toStringWithNullAsNull(Object obj) { if (obj == null) { return null; } else { return obj.toString(); } } /** * Checks if both strings are equal to each other. Safely handles the case * where either string may be null. The strings are evaluated as equal if * they are both null or if they actually equal each other. One string * that is null while the other one isn't (even if its an empty string) will * be considered as NOT equal. Case sensitive comparisons are optional. * @param string0 The string to compare * @param string1 The other string to compare with * @param caseSensitive If true a case sensitive comparison will be made, * otherwise equalsIgnoreCase will be used. * @return True if the strings are both null or equal to each other, otherwise * false. */ public static boolean isEqual(String string0, String string1, boolean caseSensitive) { if (string0 == null && string1 == null) { return true; } if (string0 == null && string1 != null) { return false; } if (string0 != null && string1 == null) { return false; } if (caseSensitive) { return string0.equals(string1); } else { return string0.equalsIgnoreCase(string1); } } public static String readToString(InputStream in) throws IOException { StringBuilder out = new StringBuilder(); byte[] b = new byte[4096]; for (int n; (n = in.read(b)) != -1;) { out.append(new String(b, 0, n)); } return out.toString(); } /** * Escapes the characters in a String using XML entities. * For example: "bread" & "butter'ed" => "bread" & "butter'ed" * * Supports the five basic XML entities (gt, lt, quot, amp, apos) and also * supports a newline and carriage return character. A newline is escaped * to and a carriage return to * * @param value The string to escape * @return The escaped String that can be used in an XML document. */ public static String escapeXml(String value) { // null to null if (value == null) return null; // assume the resulting string will be the same int len = value.length(); StringBuilder buf = new StringBuilder(len); for (int i = 0; i < len; i++) { char c = value.charAt(i); boolean entityFound = false; // is this a matching entity? for (int j = 0; j < XML_CHARS.length; j++) { // is this the matching character? if (c == XML_CHARS[j][0].charAt(0)) { // append the entity buf.append(XML_CHARS[j][1]); entityFound = true; } } if (!entityFound) { buf.append(c); } } return buf.toString(); } /** * Removes all other characters from a string except digits. A good way * of cleaing up something like a phone number. * @param str0 The string to clean up * @return A new String that has all characters except digits removed */ static public String removeAllCharsExceptDigits(String str0) { if (str0 == null) { return null; } if (str0.length() == 0) { return str0; } StringBuilder buf = new StringBuilder(str0.length()); int length = str0.length(); for (int i = 0; i < length; i++) { char c = str0.charAt(i); if (Character.isDigit(c)) { // append this character to our string buf.append(c); } } return buf.toString(); } }