package net.sourceforge.stripes.util;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.stripes.exception.StripesRuntimeException;
/**
* Provides utility methods for manipulating and parsing Strings.
*
* @author Tim Fennell
* @since Stripes 1.4.2
*/
public class StringUtil {
/**
* A regular expression for splitting apart a String where individual parts are
* separated by any whitespace (including new lines) and/or a comma.
*/
private static final Pattern STANDARD_SPLIT = Pattern.compile("[\\s,]+");
/**
* A regular expression that matches characters that are not explicitly allowed in the fragment
* part of a URI according to RFC 3986. This does not include the percent sign (%), which is
* actually allowed but only as an escape character for percent-encoded characters.
*/
private static final Pattern URI_FRAGMENT_DISALLOWED_CHARACTERS = Pattern
.compile("[^\\p{Alnum}._~!$&'()*+,;=:@/?-]");
/**
* Splits apart the input String on any whitespace and/or commas. Leading and trailing
* whitespace are ignored. If a null String is provided as input a zero length array
* will be returned.
*
* @param input the String to split apart
* @return an array of substrings of the input String based on the split
*/
public static String[] standardSplit(String input) {
if (input == null) {
return new String[0];
}
else {
return STANDARD_SPLIT.split(input.trim());
}
}
/**
* Combines a bunch of objects into a single String. Array contents get converted nicely.
*/
public static String combineParts(Object... messageParts) {
StringBuilder builder = new StringBuilder(128);
for (Object part : messageParts) {
if (part != null && part.getClass().isArray()) {
builder.append( Arrays.toString(CollectionUtil.asObjectArray(part) ));
}
else {
builder.append(part);
}
}
return builder.toString();
}
/**
* URL-encodes {@code value} using the UTF-8 charset. Using this method eliminates the need for
* a try/catch since UTF-8 is guaranteed to exist.
*
* @see URLEncoder#encode(String, String)
*/
public static String urlEncode(String value) {
try {
return URLEncoder.encode(value, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new StripesRuntimeException("Unsupported encoding? UTF-8? That's unpossible.");
}
}
/**
* URL-decodes {@code value} using the UTF-8 charset. Using this method eliminates the need for
* a try/catch since UTF-8 is guaranteed to exist.
*
* @see URLDecoder#decode(String, String)
*/
public static String urlDecode(String value) {
try {
return URLDecoder.decode(value, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new StripesRuntimeException("Unsupported encoding? UTF-8? That's unpossible.");
}
}
/**
* Encode a URI fragment as required by RFC 3986. The fragment is allowed to contain a different
* set of characters than other parts of the URI, and characters that are allowed in the
* fragment must not be encoded.
*
* @param value The string to encode
* @return The encoded string
*/
public static String uriFragmentEncode(String value) {
Matcher matcher = URI_FRAGMENT_DISALLOWED_CHARACTERS.matcher(value);
StringBuilder buf = null;
int end = 0;
while (matcher.find()) {
if (buf == null) {
buf = new StringBuilder(value.length() * 2);
}
buf.append(value.substring(end, matcher.start())).append(
String.format("%%%02X", (int) matcher.group().charAt(0)));
end = matcher.end();
}
// No match, return input unchanged
if (buf == null)
return value;
// Append tail
if (end < value.length())
buf.append(value.substring(end));
return buf.toString();
}
/**
* Return the specified URL or path string with the fragment part removed. If the string does
* not contain a fragment then return the string unchanged.
*
* @param url The URL or path
* @return The URL or path without the fragment
*/
public static String trimFragment(String url) {
if (url == null || url.length() < 1)
return url;
int index = url.indexOf('#');
if (index >= 0)
return url.substring(0, index);
else
return url;
}
}