/** * The contents of this file are subject to the Mozilla Public License * Version 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations under * the License. * * The Original Code is OpenELIS code. * * Copyright (C) The Minnesota Department of Health. All Rights Reserved. * * Contributor(s): CIRG, University of Washington, Seattle WA. */ package us.mn.state.health.lims.common.util; import org.apache.commons.validator.GenericValidator; import us.mn.state.health.lims.common.exception.LIMSRuntimeException; import us.mn.state.health.lims.common.log.LogEvent; import us.mn.state.health.lims.common.util.ConfigurationProperties.Property; import us.mn.state.health.lims.common.util.resources.ResourceLocator; import java.util.*; import java.util.regex.Pattern; /** * @author diane benz * * To change this generated comment edit the template variable * "typecomment": Window>Preferences>Java>Templates. To enable and * disable the creation of type comments go to * Window>Preferences>Java>Code Generation. */ public class StringUtil { private static final String COMMA = ","; private static final Character CHAR_COMA = ','; private static final Character CHAR_TIDDLE = '~'; private static final String TIDDLE = "~"; private static final String QUOTE = "\""; private static String STRING_KEY_SUFFIX = null; private static Pattern INTEGER_REG_EX = Pattern.compile("^-?\\d+$"); // private static SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); /** * bugzilla 2311 request parameter values coming back as string "null" when * checked for isNullorNill in an Action class need to return true */ public static boolean isNullorNill(String string) { return string == null || string.equals("") || string.equals("null"); } public static String replaceCharAtIndex( String string, char character, int index){ if( index < 0 || string == null || index >= string.length()){ return string; }else{ return string.substring(0, index) + character + string.substring(index + 1); } } /** * Search for tags in a String with oldValue tags and replace the tag with * the newValue text. * * @param input * @param oldValue * @param newValue * @return String of the text after replacement is completed */ public static String replace(String input, String oldValue, String newValue) { StringBuffer retValue = new StringBuffer(); String retString = null; if (input != null) { // Set up work string. (Extra space is so substring will work // without // extra coding when a oldValue label appears at the very end.) String workValue = input + " "; int pos; int pos_end; // Loop through the original text while there are still oldValue // tags // to be processed. pos = workValue.indexOf(oldValue); while (pos >= 0) { // If the tag is not the first character take all the text up to // the tag and append it to the new value. if (pos > 0) { retValue.append(workValue.substring(0, pos)); } // Find the closing marker for the tag pos_end = pos + (oldValue.length() - 1); // Put in the new value retValue.append(newValue); // Truncate the translated text off the front of the string and // continue workValue = workValue.substring(pos_end + 1); pos = workValue.indexOf(oldValue); } // Now append any remaining text in the work string. retValue.append(workValue); retString = retValue.toString().trim(); } return retString; } public static String replaceNullWithEmptyString(String in) { return in == null ? " " : in; } public static String[] toArray(String str) { String retArr[]; if (null == str) { retArr = new String[0]; } else { StringTokenizer tokenizer = new StringTokenizer(str, COMMA); retArr = new String[tokenizer.countTokens()]; // String token; int idx = 0; while (tokenizer.hasMoreTokens()) { retArr[idx] = tokenizer.nextToken().trim(); idx++; } } return retArr; } public static String[] toArray(String str, String delimiter) { String retArr[]; if (null == str) { retArr = new String[0]; } else { StringTokenizer tokenizer = new StringTokenizer(str, delimiter); retArr = new String[tokenizer.countTokens()]; // String token; int idx = 0; while (tokenizer.hasMoreTokens()) { retArr[idx] = tokenizer.nextToken().trim(); idx++; } } return retArr; } // from format (999)999-9999 and ext to 999/999-9999.ext public static String formatPhone(String phone, String ext) throws LIMSRuntimeException { String returnPhone = null; if (phone != null) { try { String area = phone.substring(1, 4); String pre = phone.substring(5, 8); String post = phone.substring(9, 13); returnPhone = area + "/" + pre + "-" + post; } catch (Exception e) { LogEvent.logError("StringUtil", "formatPhone()", e.toString()); } } if (!StringUtil.isNullorNill(ext)) { returnPhone = returnPhone + "." + ext; } // System.out.println("This is phone " + returnPhone); return returnPhone; } // from format 999/999-9999.ext to (999)999-9999 public static String formatPhoneForDisplay(String phone) throws LIMSRuntimeException { String returnPhone = null; if (phone != null) { try { String area = phone.substring(0, 3); String pre = phone.substring(4, 7); String post = phone.substring(8, 12); returnPhone = "(" + area + ")" + pre + "-" + post; } catch (Exception e) { LogEvent.logError("StringUtil", "formatPhoneForDisplay()", e.toString()); } } return returnPhone; } // from format 999/999-9999.ext to ext public static String formatExtensionForDisplay(String phone) throws LIMSRuntimeException { String returnPhone = null; if (phone != null) { try { returnPhone = phone.substring(13); } catch (Exception e) { LogEvent.logError("StringUtil", "formatExtensionForDisplay()", e.toString()); } } return returnPhone; } // Returns true if string s is blank from position p to the end. public static boolean isRestOfStringBlank(String s, int p) { while (p < s.length() && Character.isWhitespace(s.charAt(p))) { p++; } return p >= s.length(); } public static String convertStringToRegEx(String str) throws LIMSRuntimeException { try { String strArr[] = str.split(""); StringBuffer sb = new StringBuffer(); // discard first token for (int i = 1; i < strArr.length; i++) { sb.append("\\"); sb.append(strArr[i]); } return sb.toString(); } catch (Exception e) { LogEvent.logError("StringUtil", "convertStringToRegEx()", e.toString()); throw new LIMSRuntimeException("Error converting string to regular expression ", e); } } public static String trim(String obj) throws LIMSRuntimeException { try { if (obj != null) { return obj.trim(); } return ""; } catch (Exception e) { LogEvent.logError("StringUtil", "trim()", e.toString()); throw new LIMSRuntimeException("Error trimming string ", e); } } @SuppressWarnings({ "unchecked", "rawtypes" }) public static List loadListFromStringOfElements(String str, String textSeparator, boolean validate) throws Exception { List list = new ArrayList(); String arr[] = str.split(textSeparator); for (int i = 0; i < arr.length; i++) { String element = arr[i]; element = element.trim(); if (validate && StringUtil.isNullorNill(element)) { throw new Exception("empty data"); } list.add(element.trim()); } return list; } @SuppressWarnings({ "unchecked", "rawtypes" }) public static List createChunksOfText(String text, int maxWidth, boolean observeSpaces) throws Exception { List list = new ArrayList(); int indx; while (text != null && text.length() > 0) { if (text.length() <= maxWidth) { list.add(text); text = ""; } else { if (observeSpaces) { indx = text.indexOf(" ", maxWidth); if (indx >= 0) { list.add(text.substring(0, indx)); text = text.substring(indx); } else { list.add(text); text = ""; } } else { list.add(text.substring(0, maxWidth)); text = text.substring(maxWidth); } } } return list; } public static String getMessageForKey(String messageKey) { if (null == messageKey) { return null; } String locale = SystemConfiguration.getInstance().getDefaultLocale().toString(); return ResourceLocator.getInstance().getMessageResources().getMessage(new Locale(locale), messageKey); } public static String getMessageForKeyAndLocale(String messageKey, Locale locale) { if (null == messageKey) { return null; } return ResourceLocator.getInstance().getMessageResources().getMessage(locale, messageKey); } public static String getMessageForKeyAndLocale(String messageKey, String arg0, String arg1, Locale locale) { if (null == messageKey) { return null; } return ResourceLocator.getInstance().getMessageResources().getMessage(locale, messageKey, arg0, arg1); } public static String getMessageForKey(String messageKey, String arg) { if (null == messageKey) { return null; } String locale = SystemConfiguration.getInstance().getDefaultLocale().toString(); return ResourceLocator.getInstance().getMessageResources().getMessage(new Locale(locale), messageKey, arg); } public static String getMessageForKey(String messageKey, String arg0, String arg1) { if (null == messageKey) { return null; } String locale = SystemConfiguration.getInstance().getDefaultLocale().toString(); return ResourceLocator.getInstance().getMessageResources().getMessage(new Locale(locale), messageKey, arg0, arg1); } public static String getContextualMessageForKey(String messageKey) { if (null == messageKey) { return null; } // Note that if there is no suffix then the suffix key will be the same // as the message key // and the first search will be successful, there is no reason to test // for the suffix String suffixedKey = messageKey + getSuffix(); String suffixedValue = getMessageForKey(suffixedKey); if (!GenericValidator.isBlankOrNull(suffixedValue)) { return suffixedValue; } else { return getMessageForKey(messageKey); } } private static String getSuffix() { if (STRING_KEY_SUFFIX == null) { STRING_KEY_SUFFIX = ConfigurationProperties.getInstance().getPropertyValue(Property.StringContext); if (!GenericValidator.isBlankOrNull(STRING_KEY_SUFFIX)) { STRING_KEY_SUFFIX = "." + STRING_KEY_SUFFIX.trim(); } } return STRING_KEY_SUFFIX; } public static String getContextualKeyForKey(String key) { if (null == key) { return null; } // Note that if there is no suffix then the suffix key will be the same // as the message key // and the first search will be successful, there is no reason to test // for the suffix String suffixedKey = key + getSuffix(); String suffixedValue = getMessageForKey(suffixedKey); return GenericValidator.isBlankOrNull(suffixedValue) ? key : suffixedKey; } /* * No bounds checking for size */ public static boolean isInteger(String result) { return INTEGER_REG_EX.matcher(result).matches(); } public static boolean textInCommaSeperatedValues(String target, String csv) { if (!GenericValidator.isBlankOrNull(csv)) { String[] seperatedText = csv.split(COMMA); for (String text : seperatedText) { if (text.trim().equals(target)) { return true; } } } return false; } /** * Limit the chars in a string to the simple Java identifiers, A-Z, a-z, $, * _ etc. code taken from * http://www.exampledepot.com/egs/java.lang/IsJavaId.html * * @see Character#isJavaIdentifierPart(char) etc. for details. * @param s * - some string to test * @return True => all is well */ public static boolean isJavaIdentifier(String s) { if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) { return false; } for (int i = 1; i < s.length(); i++) { if (!Character.isJavaIdentifierPart(s.charAt(i))) { return false; } } return true; } /** * A realy dumb CSV column value escaper. It deals with imbedded commas and * double quotes, that is all. Commas means the string needs quotes around * it. Including a quote means we need to double up that character for * Excell. */ public static String escapeCSVValue(String original) { // quotes StringBuilder out = new StringBuilder(); if (GenericValidator.isBlankOrNull(original) || !original.contains(QUOTE) && !original.contains(COMMA)) { return original; } out.append(QUOTE); for (int i = 0; i < original.length(); i++) { Character c = original.charAt(i); if (c == '"') { out.append('"'); } out.append(c); } out.append(QUOTE); return out.toString(); } /** * Solves the problem of how to deal with commas within quoted strings for csv. I couldn't figure out a regex that would cover * it so we're doing it the hard way. It will stumble if '~' is embedded in the string. This will fail on mixed fields such as * 1,2,"something, else", 4,5 * */ public static String[] separateCSVWithEmbededQuotes(String line){ String[] breakOnQuotes = line.split(QUOTE); StringBuffer substitutedString = new StringBuffer(); for( String subString : breakOnQuotes){ if(subString.startsWith(COMMA)){ substitutedString.append( subString.replace(CHAR_COMA, CHAR_TIDDLE)); }else{ substitutedString.append(QUOTE); substitutedString.append(subString); substitutedString.append(QUOTE); } } return substitutedString.toString().split(TIDDLE); } /** * Similar to separateCSVWithEmbededQuotes(String line) but deals with mixed fields * i.e. 1,2,"something, else", 4,5 , "more of that thing", 8 * * */ public static String[] separateCSVWithMixedEmbededQuotes(String line){ String[] breakOnQuotes = line.split(QUOTE); StringBuffer substitutedString = new StringBuffer(); for( String subString : breakOnQuotes){ if(subString.startsWith(COMMA) || subString.endsWith(COMMA)){ substitutedString.append( subString.replace(CHAR_COMA, CHAR_TIDDLE)); }else{ substitutedString.append(QUOTE); substitutedString.append(subString); substitutedString.append(QUOTE); } } return substitutedString.toString().split(TIDDLE); } /** * Compare two strings returning the appropriate -1,0,1; but deal with * possible null strings which will compare the same as "", aka before any * other string. * * @param left left String * @param right right string * @return -1 if left is lexically less then right; 0 if they are equal; 1 * if left is lexically greater than right. */ public static int compareWithNulls(String left, String right) { if (left == null) { left = ""; } if (right == null) { right = ""; } return left.compareTo(right); } /** * Tests for equals without worrying about null. If they are both null they are equal * * @param left left String * @param right right String * @return true if they are both null or are equal */ public static boolean safeEquals(String left, String right) { if( left == right){ return true; } if (left == null) { left = ""; } if (right == null) { right = ""; } return left.equals(right); } public static String replaceAllChars(String text, char replacement) { if (text == null) { return null; } StringBuilder boringString = new StringBuilder(); for (int i = 0; i < text.length(); i++) { boringString.append(replacement); } return boringString.toString(); } public static boolean containsOnly(String text, char target) { if (text == null) { return false; } for (int i = 0; i < text.length(); i++) { if (text.charAt(i) != target) { return false; } } return true; } public static String strip(String string, String toBeRemoved){ if( string.contains(toBeRemoved)){ String[] subStrings = string.trim().split(toBeRemoved); StringBuffer reconstituted = new StringBuffer(); for( String subString : subStrings){ reconstituted.append( subString ); } return reconstituted.toString(); }else{ return string; } } public static String blankIfNull(String string) { return string == null ? "" : string; } public static String ellipsisString( String text, int ellipsisAt){ if( text.length() > ellipsisAt){ return text.substring(0, ellipsisAt) + "..."; }else{ return text; } } public static String join(Collection<String> collection, String separator){ String constructed = ""; if( collection.isEmpty()){ return constructed; } for (String item : collection) { constructed += item + separator; } return constructed.substring(0, constructed.length() - separator.length()); } public static String replaceTail(String value, String tail){ return value.substring(0, value.length() - tail.length() ) + tail; } public static String doubleWithSignificantDigits( double value, String significantDigits ){ if( GenericValidator.isBlankOrNull(significantDigits) || significantDigits.equals( "-1" )){ return String.valueOf( value ); } String format = "%1$." + significantDigits + "f"; return String.format(format, value); } public static String doubleWithSignificantDigits( double value, int significantDigits ){ String format = "%1$." + significantDigits + "f"; return String.format(format, value); } /** * Builds a delimited String from a list of values * * @param values A list of Strings to be concatenated * @param delimiter What separates the strings * @param dropBlanksAndNulls If true then keep blank and null Strings out of the list * @return String */ public static String buildDelimitedStringFromList(List<String> values, String delimiter, boolean dropBlanksAndNulls) { String delimitedString = ""; if (values == null || values.isEmpty()) return ""; int cnt = 0; for (String s : values) { if (GenericValidator.isBlankOrNull(s) && dropBlanksAndNulls) { continue; } else if (GenericValidator.isBlankOrNull(s) && !dropBlanksAndNulls) { s = ""; } if (cnt == 0) { delimitedString = s; cnt++; } else { delimitedString = delimitedString + delimiter + s; cnt++; } } return delimitedString; } public static Double doubleWithInfinity(String significantDigits) { if( GenericValidator.isBlankOrNull(significantDigits)){ return null; } if( "Infinity".equals(significantDigits)){ return Double.POSITIVE_INFINITY; } if( "-Infinity".equals(significantDigits)){ return Double.NEGATIVE_INFINITY; } try{ return new Double(significantDigits); }catch(NumberFormatException e){ LogEvent.logError("StringUtil", "doubleWithInfinity(" + significantDigits + ")", e.toString()); return null; } } }