001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.util; 018 019import static org.apache.camel.util.StringQuoteHelper.doubleQuote; 020 021/** 022 * Helper methods for working with Strings. 023 */ 024public final class StringHelper { 025 026 /** 027 * Constructor of utility class should be private. 028 */ 029 private StringHelper() { 030 } 031 032 /** 033 * Ensures that <code>s</code> is friendly for a URL or file system. 034 * 035 * @param s String to be sanitized. 036 * @return sanitized version of <code>s</code>. 037 * @throws NullPointerException if <code>s</code> is <code>null</code>. 038 */ 039 public static String sanitize(String s) { 040 return s 041 .replace(':', '-') 042 .replace('_', '-') 043 .replace('.', '-') 044 .replace('/', '-') 045 .replace('\\', '-'); 046 } 047 048 /** 049 * Counts the number of times the given char is in the string 050 * 051 * @param s the string 052 * @param ch the char 053 * @return number of times char is located in the string 054 */ 055 public static int countChar(String s, char ch) { 056 if (ObjectHelper.isEmpty(s)) { 057 return 0; 058 } 059 060 int matches = 0; 061 for (int i = 0; i < s.length(); i++) { 062 char c = s.charAt(i); 063 if (ch == c) { 064 matches++; 065 } 066 } 067 068 return matches; 069 } 070 071 /** 072 * Limits the length of a string 073 * 074 * @param s the string 075 * @param maxLength the maximum length of the returned string 076 * @return s if the length of s is less than maxLength or the first maxLength characters of s 077 */ 078 public static String limitLenght(String s, int maxLength) { 079 if (ObjectHelper.isEmpty(s)) { 080 return s; 081 } 082 return s.length() <= maxLength ? s : s.substring(0, maxLength); 083 } 084 085 public static String removeQuotes(String s) { 086 if (ObjectHelper.isEmpty(s)) { 087 return s; 088 } 089 090 s = replaceAll(s, "'", ""); 091 s = replaceAll(s, "\"", ""); 092 return s; 093 } 094 095 public static String removeLeadingAndEndingQuotes(String s) { 096 if (ObjectHelper.isEmpty(s)) { 097 return s; 098 } 099 100 String copy = s.trim(); 101 if (copy.startsWith("'") && copy.endsWith("'")) { 102 return copy.substring(1, copy.length() - 1); 103 } 104 if (copy.startsWith("\"") && copy.endsWith("\"")) { 105 return copy.substring(1, copy.length() - 1); 106 } 107 108 // no quotes, so return as-is 109 return s; 110 } 111 112 public static boolean isQuoted(String s) { 113 if (ObjectHelper.isEmpty(s)) { 114 return false; 115 } 116 117 if (s.startsWith("'") && s.endsWith("'")) { 118 return true; 119 } 120 if (s.startsWith("\"") && s.endsWith("\"")) { 121 return true; 122 } 123 124 return false; 125 } 126 127 /** 128 * Encodes the text into safe XML by replacing < > and & with XML tokens 129 * 130 * @param text the text 131 * @return the encoded text 132 */ 133 public static String xmlEncode(String text) { 134 if (text == null) { 135 return ""; 136 } 137 // must replace amp first, so we dont replace < to amp later 138 text = replaceAll(text, "&", "&"); 139 text = replaceAll(text, "\"", """); 140 text = replaceAll(text, "<", "<"); 141 text = replaceAll(text, ">", ">"); 142 return text; 143 } 144 145 /** 146 * Determines if the string has at least one letter in upper case 147 * @param text the text 148 * @return <tt>true</tt> if at least one letter is upper case, <tt>false</tt> otherwise 149 */ 150 public static boolean hasUpperCase(String text) { 151 if (text == null) { 152 return false; 153 } 154 155 for (int i = 0; i < text.length(); i++) { 156 char ch = text.charAt(i); 157 if (Character.isUpperCase(ch)) { 158 return true; 159 } 160 } 161 162 return false; 163 } 164 165 /** 166 * Determines if the string is a fully qualified class name 167 */ 168 public static boolean isClassName(String text) { 169 boolean result = false; 170 if (text != null) { 171 String[] split = text.split("\\."); 172 if (split.length > 0) { 173 String lastToken = split[split.length - 1]; 174 if (lastToken.length() > 0) { 175 result = Character.isUpperCase(lastToken.charAt(0)); 176 } 177 } 178 } 179 return result; 180 } 181 182 /** 183 * Does the expression have the language start token? 184 * 185 * @param expression the expression 186 * @param language the name of the language, such as simple 187 * @return <tt>true</tt> if the expression contains the start token, <tt>false</tt> otherwise 188 */ 189 public static boolean hasStartToken(String expression, String language) { 190 if (expression == null) { 191 return false; 192 } 193 194 // for the simple language the expression start token could be "${" 195 if ("simple".equalsIgnoreCase(language) && expression.contains("${")) { 196 return true; 197 } 198 199 if (language != null && expression.contains("$" + language + "{")) { 200 return true; 201 } 202 203 return false; 204 } 205 206 /** 207 * Replaces all the from tokens in the given input string. 208 * <p/> 209 * This implementation is not recursive, not does it check for tokens in the replacement string. 210 * 211 * @param input the input string 212 * @param from the from string, must <b>not</b> be <tt>null</tt> or empty 213 * @param to the replacement string, must <b>not</b> be empty 214 * @return the replaced string, or the input string if no replacement was needed 215 * @throws IllegalArgumentException if the input arguments is invalid 216 */ 217 public static String replaceAll(String input, String from, String to) { 218 if (ObjectHelper.isEmpty(input)) { 219 return input; 220 } 221 if (from == null) { 222 throw new IllegalArgumentException("from cannot be null"); 223 } 224 if (to == null) { 225 // to can be empty, so only check for null 226 throw new IllegalArgumentException("to cannot be null"); 227 } 228 229 // fast check if there is any from at all 230 if (!input.contains(from)) { 231 return input; 232 } 233 234 final int len = from.length(); 235 final int max = input.length(); 236 StringBuilder sb = new StringBuilder(max); 237 for (int i = 0; i < max;) { 238 if (i + len <= max) { 239 String token = input.substring(i, i + len); 240 if (from.equals(token)) { 241 sb.append(to); 242 // fast forward 243 i = i + len; 244 continue; 245 } 246 } 247 248 // append single char 249 sb.append(input.charAt(i)); 250 // forward to next 251 i++; 252 } 253 return sb.toString(); 254 } 255 256 /** 257 * Creates a json tuple with the given name/value pair. 258 * 259 * @param name the name 260 * @param value the value 261 * @param isMap whether the tuple should be map 262 * @return the json 263 */ 264 public static String toJson(String name, String value, boolean isMap) { 265 if (isMap) { 266 return "{ " + doubleQuote(name) + ": " + doubleQuote(value) + " }"; 267 } else { 268 return doubleQuote(name) + ": " + doubleQuote(value); 269 } 270 } 271 272}