blob: d6ebf093483fac12a015c0a08fde464101a5bc1d [file] [log] [blame]
/*
* 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 &gt;= 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;
}
}