| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.myfaces.util.lang; |
| |
| import java.util.ArrayList; |
| |
| |
| /** |
| * Implements utility functions for the String class |
| * |
| * <p> |
| * Emphasis on performance and reduced memory allocation/garbage collection |
| * in exchange for longer more complex code. |
| * </p> |
| */ |
| public final class StringUtils |
| { |
| private StringUtils() |
| { |
| // utility class, no instantiation |
| } |
| |
| //~ Methods ------------------------------------------------------------------------------------ |
| |
| public static boolean isEmpty(String value) |
| { |
| return value == null || value.isEmpty(); |
| } |
| |
| public static boolean isBlank(String str) |
| { |
| if (str == null) |
| { |
| return true; |
| } |
| int strLen = str.length(); |
| if (strLen == 0) |
| { |
| return true; |
| } |
| |
| for (int i = 0; i < strLen; i++) |
| { |
| if (!Character.isWhitespace(str.charAt(i))) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public static boolean isNotEmpty(String value) |
| { |
| return !isEmpty(value); |
| } |
| |
| public static boolean isNotBlank(String value) |
| { |
| return !isBlank(value); |
| } |
| |
| /** |
| * Checks that the string represents a floating point number that CANNOT be |
| * in exponential notation |
| * |
| * @param str the string to check |
| * |
| * @return boolean |
| */ |
| public static boolean isFloatNoExponent(String str) |
| { |
| int len = str.length(); |
| if (len == 0) |
| { |
| return false; |
| } |
| |
| // skip first char if sign char |
| char c = str.charAt(0); |
| int i = ((c == '-') || (c == '+')) ? 1 : 0; |
| |
| // is it only a sign? |
| if (i >= len) |
| { |
| return false; |
| } |
| |
| boolean decimalPointFound = false; |
| |
| do |
| { |
| c = str.charAt(i); |
| if (c == '.') |
| { |
| // is this a second dot? |
| if (decimalPointFound) |
| { |
| return false; |
| } |
| |
| decimalPointFound = true; |
| } |
| else if (!Character.isDigit(c)) |
| { |
| return false; |
| } |
| |
| i++; |
| } |
| while (i < len); |
| |
| return true; |
| } |
| |
| public static boolean isFloatWithOptionalExponent(String str) |
| { |
| int len = str.length(); |
| if (len == 0) |
| { |
| return false; |
| } |
| |
| // skip first char if sign char |
| char c = str.charAt(0); |
| int i = ((c == '-') || (c == '+')) ? 1 : 0; |
| |
| // is it only a sign? |
| if (i >= len) |
| { |
| return false; |
| } |
| |
| boolean exponentFound = false; |
| boolean decimalPointFound = false; |
| |
| do |
| { |
| c = str.charAt(i); |
| switch (c) |
| { |
| case '.': |
| |
| // is this a second one, are we in the exponent? |
| if (decimalPointFound || exponentFound) |
| { |
| return false; |
| } |
| decimalPointFound = true; |
| |
| break; |
| |
| case 'e': |
| case 'E': |
| |
| // is this a second one? |
| if (exponentFound) |
| { |
| return false; |
| } |
| exponentFound = true; |
| |
| // check for exponent sign |
| c = str.charAt(i + 1); |
| |
| if ((c == '-') || (c == '+')) |
| { |
| i++; |
| } |
| |
| break; |
| |
| default: |
| if (!Character.isDigit(c)) |
| { |
| return false; |
| } |
| } |
| |
| i++; |
| } |
| while (i < len); |
| |
| return true; |
| } |
| |
| public static boolean isInteger(String str) |
| { |
| int len = str.length(); |
| if (len == 0) |
| { |
| return false; |
| } |
| |
| // skip first char if sign char |
| char c = str.charAt(0); |
| int i = ((c == '-') || (c == '+')) ? 1 : 0; |
| |
| // is it only a sign? |
| if (i >= len) |
| { |
| return false; |
| } |
| |
| do |
| { |
| if (!Character.isDigit(str.charAt(i))) |
| { |
| return false; |
| } |
| i++; |
| } |
| while (i < len); |
| |
| return true; |
| } |
| |
| public static boolean isUnsignedInteger(String str) |
| { |
| int len = str.length(); |
| if (len == 0) |
| { |
| return false; |
| } |
| |
| for (int i = 0; i < len; i++) |
| { |
| if (!Character.isDigit(str.charAt(i))) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Undoubles the quotes inside the string <br> Example:<br> |
| * <pre> |
| * hello""world becomes hello"world |
| * </pre> |
| * |
| * @param str input string to dequote |
| * @param quote the quoting char |
| * |
| * @return dequoted string |
| */ |
| public static String dequote(String str, char quote) |
| { |
| // Is there anything to dequote? |
| if (str == null) |
| { |
| return null; |
| } |
| |
| return dequote(str, 0, str.length(), quote); |
| } |
| |
| /** |
| * Undoubles the quotes inside a substring <br> Example:<br> |
| * <pre> |
| * hello""world becomes hello"world |
| * </pre> |
| * WARNING: scan for quote may continue to the end of the string, make sure |
| * that either <code>charAt(end + 1) == quote</code> or <code>end = |
| * str.lentgth()</code>. If in doubt call |
| * <code>dequote(str.substring(begin, end), quote)</code> |
| * |
| * @param str input string from which to get the substring, must not be |
| * null |
| * @param begin begin index for substring |
| * @param end end index for substring |
| * @param quote the quoting char |
| * |
| * @return dequoted string |
| * |
| * @throws IllegalArgumentException if string is incorrectly quoted |
| */ |
| public static String dequote(String str, int begin, int end, char quote) |
| { |
| // Is there anything to dequote? |
| if (begin == end) |
| { |
| return ""; |
| } |
| |
| int endInt = str.indexOf(quote, begin); |
| |
| // If no quotes, return the original string |
| // and save StringBuilder allocation/char copying |
| if (endInt < 0) |
| { |
| return str.substring(begin, end); |
| } |
| |
| StringBuilder sb = new StringBuilder(end - begin); |
| int beginInt = begin; // need begin later |
| do |
| { |
| if (((endInt + 1) >= end) || (str.charAt(endInt + 1) != quote)) |
| { |
| throw new IllegalArgumentException( |
| "Internal quote not doubled in string '" |
| + str.substring(begin, end) + '\''); |
| } |
| |
| sb.append(substring(str, beginInt, endInt)).append(quote); |
| beginInt = endInt + 2; |
| endInt = str.indexOf(quote, beginInt); |
| } |
| while ((endInt >= 0) && (endInt < end)); |
| |
| return sb.append(substring(str, beginInt, end)).toString(); |
| } |
| |
| /** |
| * Removes the surrounding quote and any double quote inside the string <br> |
| * Example:<br> |
| * <pre> |
| * "hello""world" becomes hello"world |
| * </pre> |
| * |
| * @param str input string to dequote |
| * @param quote the quoting char |
| * |
| * @return dequoted String |
| */ |
| public static String dequoteFull(String str, char quote) |
| { |
| if (str == null) |
| { |
| return null; |
| } |
| |
| return dequoteFull(str, 0, str.length(), quote); |
| } |
| |
| public static String dequoteFull(String str, int begin, int end, char quote) |
| { |
| // If empty substring, return empty string |
| if (begin == end) |
| { |
| return ""; |
| } |
| |
| // If not quoted, return string |
| if (str.charAt(begin) != quote) |
| { |
| return str.substring(begin, end); |
| } |
| |
| int endInt = end - 1; |
| if ((str.length() < 2) || (str.charAt(endInt) != quote)) |
| { |
| throw new IllegalArgumentException( |
| "Closing quote missing in string '" |
| + substring(str, begin, end) + '\''); |
| } |
| |
| return dequote(str, begin + 1, endInt, quote); |
| } |
| |
| public static String replace(String str, String repl, String with) |
| { |
| int lastindex = 0; |
| int pos = str.indexOf(repl); |
| |
| // If no replacement needed, return the original string |
| // and save StringBuilder allocation/char copying |
| if (pos < 0) |
| { |
| return str; |
| } |
| |
| int len = repl.length(); |
| int lendiff = with.length() - repl.length(); |
| StringBuilder out = |
| new StringBuilder((lendiff <= 0) ? str.length() |
| : (str.length() + (10 * lendiff))); |
| while(pos >= 0) |
| { |
| out.append(substring(str, lastindex, pos)).append(with); |
| lastindex = pos + len; |
| pos = str.indexOf(repl, lastindex); |
| } |
| |
| return out.append(substring(str, lastindex, str.length())).toString(); |
| } |
| |
| public static String replace(String str, char repl, String with) |
| { |
| int pos = str.indexOf(repl); |
| |
| // If no replacement needed, return the original string |
| // and save StringBuilder allocation/char copying |
| if (pos < 0) |
| { |
| return str; |
| } |
| |
| int len = str.length(); |
| int lendiff = with.length() - 1; |
| StringBuilder out = |
| new StringBuilder((lendiff <= 0) ? str.length() |
| : (str.length() + (10 * lendiff))); |
| int lastindex = 0; |
| while( pos >= 0) |
| { |
| out.append(substring(str, lastindex, pos)).append(with); |
| lastindex = pos + 1; |
| pos = str.indexOf(repl, lastindex); |
| } |
| |
| return out.append(substring(str, lastindex, len)).toString(); |
| } |
| |
| public static StringBuffer replace( |
| StringBuffer out, String s, String repl, String with) |
| { |
| int lastindex = 0; |
| int len = repl.length(); |
| int index = s.indexOf(repl); |
| while (index >= 0) |
| { |
| // we have search string at position index |
| out.append(substring(s, lastindex, index)).append(with); |
| lastindex = index + len; |
| index = s.indexOf(repl, lastindex); |
| } |
| |
| return out.append(substring(s, lastindex, len)); |
| } |
| |
| public static StringBuilder replace( |
| StringBuilder out, String s, String repl, String with) |
| { |
| int lastindex = 0; |
| int len = repl.length(); |
| int index = s.indexOf(repl); |
| while (index >= 0) |
| { |
| // we have search string at position index |
| out.append(substring(s, lastindex, index)).append(with); |
| lastindex = index + len; |
| index = s.indexOf(repl, lastindex); |
| } |
| |
| return out.append(substring(s, lastindex, len)); |
| } |
| |
| /** |
| * Split a string into an array of strings arround a character separator. |
| * This function will be efficient for longer strings |
| * |
| * @param str the string to be split |
| * @param separator the separator character |
| * |
| * @return array of string subparts |
| */ |
| public static String[] splitLongString(String str, char separator) |
| { |
| int len = (str == null) ? 0 : str.length(); |
| if (str == null || len == 0) |
| { |
| return ArrayUtils.EMPTY_STRING_ARRAY; |
| } |
| |
| int oldPos = 0; |
| ArrayList list = new ArrayList(); |
| int pos = str.indexOf(separator); |
| while(pos >= 0) |
| { |
| list.add(substring(str, oldPos, pos)); |
| oldPos = (pos + 1); |
| pos = str.indexOf(separator, oldPos); |
| } |
| |
| |
| list.add(substring(str, oldPos, len)); |
| |
| return (String[]) list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); |
| } |
| |
| /** |
| * Split a string into an array of strings arround a character separator. |
| * Each element can be optionally quoted by the quote character.<br> |
| * This function will be efficient for long strings |
| * |
| * @param str the string to be split |
| * @param separator the separator character |
| * @param quote the quote character |
| * |
| * @return array of string subparts |
| * |
| * @throws IllegalArgumentException DOCUMENT ME! |
| */ |
| public static String[] splitLongString( |
| String str, char separator, char quote) |
| { |
| int len = (str == null) ? 0 : str.length(); |
| if (str == null || len == 0) |
| { |
| return ArrayUtils.EMPTY_STRING_ARRAY; |
| } |
| |
| int oldPos = 0; |
| ArrayList list = new ArrayList(); |
| for (int pos = 0; pos < len; oldPos = ++pos) |
| { |
| // Skip quoted text, if any |
| while ((pos < len) && (str.charAt(pos) == quote)) |
| { |
| pos = str.indexOf(quote, pos + 1) + 1; |
| |
| if (pos == 0) |
| { |
| throw new IllegalArgumentException( |
| "Closing quote missing in string '" + str + '\''); |
| } |
| } |
| |
| boolean quoted; |
| |
| if (pos != oldPos) |
| { |
| quoted = true; |
| |
| if ((pos < len) && (str.charAt(pos) != separator)) |
| { |
| throw new IllegalArgumentException( |
| "Separator must follow closing quote in string '" |
| + str + '\''); |
| } |
| } |
| else |
| { |
| quoted = false; |
| pos = str.indexOf(separator, pos); |
| if (pos < 0) |
| { |
| pos = len; |
| } |
| } |
| |
| list.add( |
| quoted ? dequote(str, oldPos + 1, pos - 1, quote) |
| : substring(str, oldPos, pos)); |
| } |
| |
| return (String[]) list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); |
| } |
| |
| /** |
| * Split a string into an array of strings arround a character separator. |
| * This function will be efficient for short strings, for longer strings, |
| * another approach may be better |
| * |
| * @param str the string to be split |
| * @param separator the separator character |
| * |
| * @return array of string subparts |
| */ |
| public static String[] splitShortString(String str, char separator) |
| { |
| int len = (str == null) ? 0 : str.length(); |
| if (str == null || len == 0) |
| { |
| return org.apache.myfaces.util.lang.ArrayUtils.EMPTY_STRING_ARRAY; |
| } |
| |
| int lastTokenIndex = 0; |
| |
| // Step 1: how many substrings? |
| // We exchange double scan time for less memory allocation |
| for (int pos = str.indexOf(separator); |
| pos >= 0; pos = str.indexOf(separator, pos + 1)) |
| { |
| lastTokenIndex++; |
| } |
| |
| // Step 2: allocate exact size array |
| String[] list = new String[lastTokenIndex + 1]; |
| |
| int oldPos = 0; |
| |
| // Step 3: retrieve substrings |
| int pos = str.indexOf(separator); |
| int i = 0; |
| |
| while (pos >= 0) |
| { |
| list[i++] = substring(str, oldPos, pos); |
| oldPos = (pos + 1); |
| pos = str.indexOf(separator, oldPos); |
| } |
| |
| list[lastTokenIndex] = substring(str, oldPos, len); |
| |
| return list; |
| } |
| |
| /** |
| * Split a string into an array of strings arround a character separator. |
| * Each element can be optionally quoted by the quote character.<br> |
| * This function will be efficient for short strings, for longer strings, |
| * another approach may be better |
| * |
| * @param str the string to be split |
| * @param separator the separator character |
| * @param quote the quote character |
| * |
| * @return array of string subparts |
| * |
| * @throws IllegalArgumentException DOCUMENT ME! |
| */ |
| public static String[] splitShortString( |
| String str, char separator, char quote) |
| { |
| int len = (str == null) ? 0 : str.length(); |
| if (str == null || len == 0) |
| { |
| return ArrayUtils.EMPTY_STRING_ARRAY; |
| } |
| |
| // Step 1: how many substrings? |
| // We exchange double scan time for less memory allocation |
| int tokenCount = 0; |
| for (int pos = 0; pos < len; pos++) |
| { |
| tokenCount++; |
| |
| int oldPos = pos; |
| |
| // Skip quoted text, if any |
| while ((pos < len) && (str.charAt(pos) == quote)) |
| { |
| pos = str.indexOf(quote, pos + 1) + 1; |
| |
| // pos == 0 is not found (-1 returned by indexOf + 1) |
| if (pos == 0) |
| { |
| throw new IllegalArgumentException( |
| "Closing quote missing in string '" + str + '\''); |
| } |
| } |
| |
| if (pos != oldPos) |
| { |
| if ((pos < len) && (str.charAt(pos) != separator)) |
| { |
| throw new IllegalArgumentException( |
| "Separator must follow closing quote in strng '" |
| + str + '\''); |
| } |
| } |
| else |
| { |
| pos = str.indexOf(separator, pos); |
| if (pos < 0) |
| { |
| break; |
| } |
| } |
| } |
| |
| // Main loop will finish one substring short when last char is separator |
| if (str.charAt(len - 1) == separator) |
| { |
| tokenCount++; |
| } |
| |
| // Step 2: allocate exact size array |
| String[] list = new String[tokenCount]; |
| |
| // Step 3: retrieve substrings |
| // Note: on this pass we do not check for correctness, |
| // since we have already done so |
| tokenCount--; // we want to stop one token short |
| |
| int oldPos = 0; |
| for (int pos = 0, i = 0; i < tokenCount; i++, oldPos = ++pos) |
| { |
| boolean quoted; |
| |
| // Skip quoted text, if any |
| while (str.charAt(pos) == quote) |
| { |
| pos = str.indexOf(quote, pos + 1) + 1; |
| } |
| |
| if (pos != oldPos) |
| { |
| quoted = true; |
| |
| if (str.charAt(pos) != separator) |
| { |
| throw new IllegalArgumentException( |
| "Separator must follow closing quote in strng '" |
| + str + '\''); |
| } |
| } |
| else |
| { |
| quoted = false; |
| pos = str.indexOf(separator, pos); |
| } |
| |
| list[i] = |
| quoted ? dequote(str, oldPos + 1, pos - 1, quote) |
| : substring(str, oldPos, pos); |
| } |
| |
| list[tokenCount] = dequoteFull(str, oldPos, len, quote); |
| |
| return list; |
| } |
| |
| public static String substring(String str, int begin, int end) |
| { |
| if (begin == end) |
| { |
| return ""; |
| } |
| |
| return str.substring(begin, end); |
| } |
| |
| public static String[] trim(String[] strings) |
| { |
| if (strings == null) |
| { |
| return null; |
| } |
| |
| for (int i = 0, len = strings.length; i < len; i++) |
| { |
| strings[i] = strings[i].trim(); |
| } |
| |
| return strings; |
| } |
| |
| /** |
| * Returns the minimum index >= 0, if any |
| * |
| * <p> |
| * Use to find the first of two characters in a string:<br> |
| * <code>minIndex(s.indexOf('/'), indexOf('\'))</code> |
| * </p> |
| * |
| * @param a |
| * @param b |
| * @return |
| */ |
| public static int minIndex(int a, int b) |
| { |
| return (a < 0) ? b |
| : (b < 0) ? a |
| : (a < b) ? a : b; |
| } |
| } |