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 public static String removeQuotes(String s) { 072 if (ObjectHelper.isEmpty(s)) { 073 return s; 074 } 075 076 s = replaceAll(s, "'", ""); 077 s = replaceAll(s, "\"", ""); 078 return s; 079 } 080 081 public static String removeLeadingAndEndingQuotes(String s) { 082 if (ObjectHelper.isEmpty(s)) { 083 return s; 084 } 085 086 String copy = s.trim(); 087 if (copy.startsWith("'") && copy.endsWith("'")) { 088 return copy.substring(1, copy.length() - 1); 089 } 090 if (copy.startsWith("\"") && copy.endsWith("\"")) { 091 return copy.substring(1, copy.length() - 1); 092 } 093 094 // no quotes, so return as-is 095 return s; 096 } 097 098 public static boolean isQuoted(String s) { 099 if (ObjectHelper.isEmpty(s)) { 100 return false; 101 } 102 103 if (s.startsWith("'") && s.endsWith("'")) { 104 return true; 105 } 106 if (s.startsWith("\"") && s.endsWith("\"")) { 107 return true; 108 } 109 110 return false; 111 } 112 113 /** 114 * Encodes the text into safe XML by replacing < > and & with XML tokens 115 * 116 * @param text the text 117 * @return the encoded text 118 */ 119 public static String xmlEncode(String text) { 120 if (text == null) { 121 return ""; 122 } 123 // must replace amp first, so we dont replace < to amp later 124 text = replaceAll(text, "&", "&"); 125 text = replaceAll(text, "\"", """); 126 text = replaceAll(text, "<", "<"); 127 text = replaceAll(text, ">", ">"); 128 return text; 129 } 130 131 /** 132 * Determines if the string has at least one letter in upper case 133 * @param text the text 134 * @return <tt>true</tt> if at least one letter is upper case, <tt>false</tt> otherwise 135 */ 136 public static boolean hasUpperCase(String text) { 137 if (text == null) { 138 return false; 139 } 140 141 for (int i = 0; i < text.length(); i++) { 142 char ch = text.charAt(i); 143 if (Character.isUpperCase(ch)) { 144 return true; 145 } 146 } 147 148 return false; 149 } 150 151 /** 152 * Determines if the string is a fully qualified class name 153 */ 154 public static boolean isClassName(String text) { 155 boolean result = false; 156 if (text != null) { 157 String[] split = text.split("\\."); 158 if (split.length > 0) { 159 String lastToken = split[split.length - 1]; 160 if (lastToken.length() > 0) { 161 result = Character.isUpperCase(lastToken.charAt(0)); 162 } 163 } 164 } 165 return result; 166 } 167 168 /** 169 * Does the expression have the language start token? 170 * 171 * @param expression the expression 172 * @param language the name of the language, such as simple 173 * @return <tt>true</tt> if the expression contains the start token, <tt>false</tt> otherwise 174 */ 175 public static boolean hasStartToken(String expression, String language) { 176 if (expression == null) { 177 return false; 178 } 179 180 // for the simple language the expression start token could be "${" 181 if ("simple".equalsIgnoreCase(language) && expression.contains("${")) { 182 return true; 183 } 184 185 if (language != null && expression.contains("$" + language + "{")) { 186 return true; 187 } 188 189 return false; 190 } 191 192 /** 193 * Replaces all the from tokens in the given input string. 194 * <p/> 195 * This implementation is not recursive, not does it check for tokens in the replacement string. 196 * 197 * @param input the input string 198 * @param from the from string, must <b>not</b> be <tt>null</tt> or empty 199 * @param to the replacement string, must <b>not</b> be empty 200 * @return the replaced string, or the input string if no replacement was needed 201 * @throws IllegalArgumentException if the input arguments is invalid 202 */ 203 public static String replaceAll(String input, String from, String to) { 204 if (ObjectHelper.isEmpty(input)) { 205 return input; 206 } 207 if (from == null) { 208 throw new IllegalArgumentException("from cannot be null"); 209 } 210 if (to == null) { 211 // to can be empty, so only check for null 212 throw new IllegalArgumentException("to cannot be null"); 213 } 214 215 // fast check if there is any from at all 216 if (!input.contains(from)) { 217 return input; 218 } 219 220 final int len = from.length(); 221 final int max = input.length(); 222 StringBuilder sb = new StringBuilder(max); 223 for (int i = 0; i < max;) { 224 if (i + len <= max) { 225 String token = input.substring(i, i + len); 226 if (from.equals(token)) { 227 sb.append(to); 228 // fast forward 229 i = i + len; 230 continue; 231 } 232 } 233 234 // append single char 235 sb.append(input.charAt(i)); 236 // forward to next 237 i++; 238 } 239 return sb.toString(); 240 } 241 242 /** 243 * Creates a json tuple with the given name/value pair. 244 * 245 * @param name the name 246 * @param value the value 247 * @param isMap whether the tuple should be map 248 * @return the json 249 */ 250 public static String toJson(String name, String value, boolean isMap) { 251 if (isMap) { 252 return "{ " + doubleQuote(name) + ": " + doubleQuote(value) + " }"; 253 } else { 254 return doubleQuote(name) + ": " + doubleQuote(value); 255 } 256 } 257 258}