/** * */ package com.trendrr.oss; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.SecureRandom; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.*; import com.trendrr.oss.concurrent.LazyInit; /** * @author dustin * */ public class StringHelper { public static void main(String...strings) { } /** * joins a list into a string. similar to methods available IN ANY OTHER LANGUAGE * @param lst * @param delim * @return */ public static String join(Collection lst, String delim) { return joinCol(lst, delim); } public static String join(List lst, String delim) { //this method should not be necessary, but exceptions thrown in test env show that it is.. //strange.. return joinCol((Collection)lst, delim); } /** * split into separate method so we don't get any accidental recursion * between join(list) and join(collection). * @param lst * @param delim * @return */ private static String joinCol(Collection lst, String delim) { StringBuilder builder = new StringBuilder(); for (Object obj : lst) { if (obj != null) builder.append(obj.toString()); builder.append(delim); } builder.delete(builder.length()-delim.length(), builder.length()); return builder.toString(); } public static String underscoreSpaces(String input) { if (input == null) return null; String tmp = input.trim().replaceAll("\\s+", "_"); tmp = tmp.replaceAll("_+", "_"); return tmp; } public static String reverse(String input) { StringBuffer buf = new StringBuffer(input); return buf.reverse().toString(); } /** * capitalizes the first letter. * @param input * @return */ public static String capitalize(String input) { if (input == null || input.isEmpty()) return input; return input.substring(0, 1).toUpperCase() + input.substring(1); } /** * lower cases the first letter * @param input * @return */ public static String uncapitalize(String input) { if (input == null || input.isEmpty()) return input; return input.substring(0, 1).toLowerCase() + input.substring(1); } public static String capitalizeWords(String input) { String [] tmp = input.split("\\s+"); String retVal = ""; for (String word : tmp) { retVal += capitalize(word) + " "; } return retVal.trim(); } public static String singularize(String input) { String str = input; if (str.endsWith("s")) str = str.substring(0, str.length() -1); return str; } /** * Does a simple string compare, ignoring case and punctuation. * @param str1 * @param str2 * @return */ public static boolean like(String str1, String str2) { String tmp1 = prepareStringSearch(str1); String tmp2 = prepareStringSearch(str1); return tmp1.equals(tmp2); } /** * Does a simple string search to see if str1 contains str2. * Ignores case, punctuation * * @param str1 * @param str2 * @return */ private static String prepareStringSearch(String str) { // add a space at the beginning to make stripping 'a', 'the' ect easier. String tmp = " " + str.toLowerCase(); tmp = tmp.replaceAll("\\s\\&\\s", " and "); tmp = tmp.replaceAll("[\\,\\-]", " "); tmp = tmp.replaceAll("[^a-z0-9\\s]", ""); tmp = tmp.replaceAll("\\sthe\\s", " "); tmp = tmp.replaceAll("\\sa\\s", " "); tmp = tmp.replaceAll("\\sto\\s", " "); tmp = tmp.trim().replaceAll("\\s+", " "); return tmp; } /** * Checks if str1 contains str2. * ignores case and punctuation and words 'the' 'a' 'to'. * * if wordBoundaries is true then it only returns true on word matches: * ie. * * wordBoundaries = true : "jon johnson" matches "jon" or "johnson" * wordBoundaries = false : matches all from above plus "john" "hnson" ect.. * @param str1 * @param str2 * @param wordBoundaries * @return */ public static boolean contains(String str1, String str2, boolean wordBoundaries) { String tmp1 = (wordBoundaries?" ":"") + prepareStringSearch(str1) + (wordBoundaries?" ":""); String tmp2 = (wordBoundaries?" ":"") + prepareStringSearch(str2) + (wordBoundaries?" ":""); return tmp1.indexOf(tmp2) != -1; } public static final char[] CHARACTERS = { //indexes 'A','B','C','D','E','F','G','H', //0-7 'I','J','K','L','M','N','O','P', //8-15 'Q','R','S','T','U','V','W','X', //16-23 'Y','Z','a','b','c','d','e','f', //24-31 'g','h','i','j','k','l','m','n', //32-39 'o','p','q','r','s','t','u','v', //40-47 'w','x','y','z','0','1','2','3', //48-55 '4','5','6','7','8','9' //56-61 }; /** * Generates a random string of length length, * containing a-z, A-Z, 0-9 * */ public static String getRandomString(int length) { Random generator = new Random(); char str[] = new char[length]; for (int i=0; i < length; i++) { str[i] = CHARACTERS[generator.nextInt(CHARACTERS.length)]; } return new String (str); } public static String toHex(byte[] bytes) { StringBuffer hexString = new StringBuffer(); for (int i=0;i<bytes.length;i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { // could use a for loop, but we're only dealing with a single byte hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } /** * removes all bad characters not suitable for UTF-8 encoding */ public static String toUTF8String(String str){ if(str==null) return null; return str.replaceAll( "([\\ud800-\\udbff\\udc00-\\udfff])", ""); } /** * randomizes a string ordering. probably could be faster * @param str * @return */ public static String shuffle(String str) { if (str.length()<=1) return str; int split=str.length()/2; String temp1=shuffle(str.substring(0,split)); String temp2=shuffle(str.substring(split)); if (Math.random() > 0.5) return temp1 + temp2; else return temp2 + temp1; } /** * Generates a random string of length length, * containing a-z, A-Z, 0-9 * */ public static String randomString(int length) { return getRandomString(length); } public static String getRandomNumberString(int length) { Random generator = new Random(); char str[] = new char[length]; for (int i=0; i < length; i++) { str[i] = CHARACTERS[51 + generator.nextInt(10)]; } return new String (str); } /** * escapes the string for use in javascript * @param input * @return */ public static String javascriptEscape(String input) { if (input == null) return null; String tmp = input.replaceAll("'", "\\'"); tmp = tmp.replaceAll("\"", "\\\""); return tmp; } public static String camelize(String word) { return camelize(word, false); } /** * camel cases the passed in string. spaces and underscores are removed and trigger a capitalization. * @param word * @return */ public static String camelize(String word, boolean lowercaseFirstLetter) { if (word == null) return null; String[] words = word.split("[\\s_]+"); StringBuffer buf = new StringBuffer(); if (lowercaseFirstLetter) { buf.append(words[0].substring(0, 1).toLowerCase() + words[0].substring(1)); } else { buf.append(capitalize(words[0])); } for (int i=1; i < words.length; i++) { buf.append(capitalize(words[i])); } return buf.toString(); } /** * uncamelizes the input string. * does not lowercase anything, just adds a space infront of any capitals * @param input * @return */ public static String uncamelize(String input) { StringBuilder buf = new StringBuilder(); for (char c : input.toCharArray()) { if (Character.isUpperCase(c)) buf.append(' '); buf.append(c); } return buf.toString().trim(); } /** * returns true if the input contains one or more of the delimiters. * @param input * @param delimiters * @return */ public static boolean contains(String input, String ... delimiters) { if (input == null || delimiters == null) return false; for (String s : delimiters) { if (input.contains(s)) return true; } return false; } /** * returns true if the input is equal to one of the passed in strs. * @param input * @param delimiters * @return */ public static boolean equals(String input, boolean ignoreCase, String ... str) { if (input == null || str == null) return false; for (String s : str) { if (ignoreCase) { if (input.equalsIgnoreCase(s)) { return true; } } else { if (input.equals(s)) return true; } } return false; } public static String toPrettyString(Map map) { StringBuffer buf = new StringBuffer(); buf.append("{"); for (Object key: map.keySet()) { buf.append(key.toString()); buf.append(" : "); Object val = map.get(key); if (val == null) { buf.append("null"); } else if (val instanceof String[]) { buf.append(toPrettyString((String[])val)); } else { buf.append(val.toString()); } buf.append(", "); } if (buf.length() > 1) { buf.deleteCharAt(buf.length()-1); buf.deleteCharAt(buf.length()-1); } buf.append("}"); return buf.toString(); } public static String toPrettyString(String[] array) { StringBuffer buf = new StringBuffer(); buf.append("["); for (String st: array) { buf.append(st); buf.append(","); } if (buf.length() > 1); buf.deleteCharAt(buf.length()-1); buf.append("]"); return buf.toString(); } /** * trims the specified number of chars off the END of the string. If num > input.length then * a zero length string is returned. * @param input * @param num * @return */ public static String trimChars(String input, int num) { if (input == null) return null; if (num >= input.length()) return ""; return input.substring(0, input.length() - num); } /** * will trim off the front and back of the string. * * if trim = " " then it is the same as str.trim() * * @param input * @param trim * @return */ public static String trim(String input, String trim) { if (input == null || trim == null || trim.isEmpty()) return input; String tmp = input; while(tmp.startsWith(trim)) { tmp = tmp.substring(trim.length()); } while(tmp.endsWith(trim)) { tmp = tmp.substring(0, tmp.length()-trim.length()); } return tmp; } /** * will return a string with max nmber of characters * @param input * @param max * @return */ public static String maxChars(String input, int max) { if (input == null) return null; if (max >= input.length()) return input; return input.substring(0, max); } public static String removeAll(String input, Collection toRemove) { String ret = input; for (Object str : toRemove) { ret = ret.replace(str.toString(), ""); } return ret; } /** * removes all instances of the inputed strings. strings are matches not regexes. * @param input * @param strings * @return */ public static String removeAll(String input, String ...toRemove ) { String ret = input; for (String str : toRemove) { ret = ret.replace(str, ""); } return ret; } /** * removes all the requested characters. * Implemented to be optimally fast. * * @param input * @param toRemove * @return */ public static String removeAll(String input, char ...toRemove ) { if (input == null) return null; Set<Character> toRem = new HashSet<Character>(); for (char c : toRemove) { toRem.add(c); } StringBuilder build = new StringBuilder(); StringCharacterIterator iter = new StringCharacterIterator(input); for(char c = iter.first(); c != StringCharacterIterator.DONE; c = iter.next()) { if (toRem.contains(c)) continue; build.append(c); } return build.toString(); } /** * returns true if input equals one of the passed in strings. * @param input * @param val * @return */ public static boolean matches(String input, String ...vals) { if (input == null) return false; for (String val : vals) { if (input.equals(val)) return true; } return false; } /** * splits the string based on the given delimiters. * * * @param input * @param delimiters * @return */ public static List<String> split(String input, String ...delimiters) { if (input == null) return null; String str = input; List<String> list = new ArrayList<String>(); String delim = delimiters[0]; for (int i=1; i < delimiters.length; i++) { str = str.replaceAll(delimiters[i], delim); } String[] tmp = str.split(delim); for (int i=0; i < tmp.length; i++) { list.add(tmp[i].trim()); } return list; } /** * Just strips any non allowed characters. * * currently allow letters, digits and * * $ - _ . + ! * ' ( ) , { } | \ ^ ~ [ ] ` " > < # % ; / ? & = * * @param url * @return */ public static String sanitizeUrl(String url) { StringBuilder str = new StringBuilder(); CharacterIterator ci = new StringCharacterIterator(url); for (char ch = ci.first(); ch != CharacterIterator.DONE; ch = ci.next()) { if (Character.isLetterOrDigit(ch)) { str.append(ch); continue; } //we could do this with a regex, but would be unreadable, and I believe this //is faster. switch (ch) { case '$' : str.append(ch); continue; case '-' : str.append(ch); continue; case '_' : str.append(ch); continue; case '.' : str.append(ch); continue; case '+' : str.append(ch); continue; case '!' : str.append(ch); continue; case '*' : str.append(ch); continue; case '\'' : str.append(ch); continue; case '(' : str.append(ch); continue; case ')' : str.append(ch); continue; case ',' : str.append(ch); continue; case '{' : str.append(ch); continue; case '}' : str.append(ch); continue; case '|' : str.append(ch); continue; case '\\' : str.append(ch); continue; case '^' : str.append(ch); continue; case '~' : str.append(ch); continue; case '[' : str.append(ch); continue; case ']' : str.append(ch); continue; case '`' : str.append(ch); continue; case '\"' : str.append(ch); continue; case '<' : str.append(ch); continue; case '>' : str.append(ch); continue; case '#' : str.append(ch); continue; case '%' : str.append(ch); continue; case ';' : str.append(ch); continue; case '/' : str.append(ch); continue; case '?' : str.append(ch); continue; } } return str.toString(); } /** * returns a 20 byte sha1 hash * @param bytes * @return * @deprecated moved to HashFunctions */ @Deprecated public static byte[] sha1(byte[] bytes) { try { MessageDigest sha = MessageDigest.getInstance("SHA-1"); byte[] result = sha.digest( bytes ); return result; } catch (Exception x) { } return null; } /** * @deprecated moved to HashFunctions */ @Deprecated public static String sha1Hex(byte[] bytes) { return toHex(sha1(bytes)); } private static LazyInit lock = new LazyInit(); private static SecureRandom prng = null; /** * Generates a cryptographically secure ID. * * Should reasonably be unique, though that is not guarenteed. * * result is 20 bytes long. * * * @deprecated moved to HashFunctions */ @Deprecated public static byte[] secureId() { try { if (lock.start()) { try { //initialize the secure random only once //as it is a lengthy op. prng = SecureRandom.getInstance("SHA1PRNG"); } finally { lock.end(); } } int numBytes = 64; //upper 8 bytes is the timestamp, to attempt uniqueness Long millis = new Date().getTime(); byte[] randBytes = new byte[numBytes - 8]; prng.nextBytes(randBytes); ByteBuffer buf = ByteBuffer.allocate(numBytes); buf.putLong(millis); buf.put(randBytes); //get its digest return sha1(buf.array()); } catch (Exception x) { x.printStackTrace(); } return null; } }