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 019/** 020 * Helper methods for working with Strings. 021 */ 022public final class StringHelper { 023 024 /** 025 * Constructor of utility class should be private. 026 */ 027 private StringHelper() { 028 } 029 030 /** 031 * Ensures that <code>s</code> is friendly for a URL or file system. 032 * 033 * @param s String to be sanitized. 034 * @return sanitized version of <code>s</code>. 035 * @throws NullPointerException if <code>s</code> is <code>null</code>. 036 */ 037 public static String sanitize(String s) { 038 return s 039 .replace(':', '-') 040 .replace('_', '-') 041 .replace('.', '-') 042 .replace('/', '-') 043 .replace('\\', '-'); 044 } 045 046 /** 047 * Counts the number of times the given char is in the string 048 * 049 * @param s the string 050 * @param ch the char 051 * @return number of times char is located in the string 052 */ 053 public static int countChar(String s, char ch) { 054 if (ObjectHelper.isEmpty(s)) { 055 return 0; 056 } 057 058 int matches = 0; 059 for (int i = 0; i < s.length(); i++) { 060 char c = s.charAt(i); 061 if (ch == c) { 062 matches++; 063 } 064 } 065 066 return matches; 067 } 068 069 public static String removeQuotes(String s) { 070 if (ObjectHelper.isEmpty(s)) { 071 return s; 072 } 073 074 s = s.replaceAll("'", ""); 075 s = s.replaceAll("\"", ""); 076 return s; 077 } 078 079 public static String removeLeadingAndEndingQuotes(String s) { 080 if (ObjectHelper.isEmpty(s)) { 081 return s; 082 } 083 084 String copy = s.trim(); 085 if (copy.startsWith("'") && copy.endsWith("'")) { 086 return copy.substring(1, copy.length() - 1); 087 } 088 if (copy.startsWith("\"") && copy.endsWith("\"")) { 089 return copy.substring(1, copy.length() - 1); 090 } 091 092 // no quotes, so return as-is 093 return s; 094 } 095 096 public static boolean isQuoted(String s) { 097 if (ObjectHelper.isEmpty(s)) { 098 return false; 099 } 100 101 if (s.startsWith("'") && s.endsWith("'")) { 102 return true; 103 } 104 if (s.startsWith("\"") && s.endsWith("\"")) { 105 return true; 106 } 107 108 return false; 109 } 110 111 /** 112 * Encodes the text into safe XML by replacing < > and & with XML tokens 113 * 114 * @param text the text 115 * @return the encoded text 116 */ 117 public static String xmlEncode(String text) { 118 if (text == null) { 119 return ""; 120 } 121 // must replace amp first, so we dont replace < to amp later 122 return text.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">"); 123 } 124 125 /** 126 * Determines if the string has at least one letter in upper case 127 * @param text the text 128 * @return <tt>true</tt> if at least one letter is upper case, <tt>false</tt> otherwise 129 */ 130 public static boolean hasUpperCase(String text) { 131 if (text == null) { 132 return false; 133 } 134 135 for (int i = 0; i < text.length(); i++) { 136 char ch = text.charAt(i); 137 if (Character.isUpperCase(ch)) { 138 return true; 139 } 140 } 141 142 return false; 143 } 144 145 /** 146 * Does the expression have the language start token? 147 * 148 * @param expression the expression 149 * @param language the name of the language, such as simple 150 * @return <tt>true</tt> if the expression contains the start token, <tt>false</tt> otherwise 151 */ 152 public static boolean hasStartToken(String expression, String language) { 153 if (expression == null) { 154 return false; 155 } 156 157 // for the simple language the expression start token could be "${" 158 if ("simple".equalsIgnoreCase(language) && expression.indexOf("${") >= 0) { 159 return true; 160 } 161 162 if (language != null && expression.indexOf("$" + language + "{") >= 0) { 163 return true; 164 } 165 166 return false; 167 } 168 169 /** 170 * Replaces all the from tokens in the given input string. 171 * <p/> 172 * This implementation is not recursive, not does it check for tokens in the replacement string. 173 * 174 * @param input the input string 175 * @param from the from string, must <b>not</b> be <tt>null</tt> or empty 176 * @param to the replacement string, must <b>not</b> be empty 177 * @return the replaced string, or the input string if no replacement was needed 178 * @throws IllegalArgumentException if the input arguments is invalid 179 */ 180 public static String replaceAll(String input, String from, String to) { 181 if (ObjectHelper.isEmpty(input)) { 182 return input; 183 } 184 if (from == null) { 185 throw new IllegalArgumentException("from cannot be null"); 186 } 187 if (to == null) { 188 // to can be empty, so only check for null 189 throw new IllegalArgumentException("to cannot be null"); 190 } 191 192 // fast check if there is any from at all 193 if (!input.contains(from)) { 194 return input; 195 } 196 197 final int len = from.length(); 198 final int max = input.length(); 199 StringBuilder sb = new StringBuilder(max); 200 for (int i = 0; i < max;) { 201 if (i + len <= max) { 202 String token = input.substring(i, i + len); 203 if (from.equals(token)) { 204 sb.append(to); 205 // fast forward 206 i = i + len; 207 continue; 208 } 209 } 210 211 // append single char 212 sb.append(input.charAt(i)); 213 // forward to next 214 i++; 215 } 216 return sb.toString(); 217 } 218 219}