/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.utils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
/**
* Helper class for handling strings
* @author Jefferson Magno
*/
public class StringHelper {
private static final String MASK_VARIABLES = "#09aAlLuUcC?_";
private static final String DIGITS = "0123456789";
private static final String LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz";
private static final String UPERCASE_LETTERS = LOWERCASE_LETTERS.toUpperCase();
private static final String LETTERS = LOWERCASE_LETTERS + UPERCASE_LETTERS;
/**
* Removes the given mask from the given value
*/
public static String applyMask(final String mask, final String value) {
if (StringUtils.isEmpty(mask) || value == null) {
return value;
}
final StringBuilder sb = new StringBuilder();
boolean nextIsLiteral = false;
int pos = 0;
for (int i = 0; i < mask.length(); i++) {
final char c = mask.charAt(i);
if (c == '\\') {
nextIsLiteral = true;
} else if (!nextIsLiteral && MASK_VARIABLES.indexOf(c) >= 0) {
try {
sb.append(value.charAt(pos++));
} catch (final StringIndexOutOfBoundsException e) {
continue;
}
} else {
nextIsLiteral = false;
sb.append(c);
if (Character.isLetterOrDigit(c)) {
pos++;
}
}
}
return sb.toString();
}
/**
* Decodes the url
*/
public static String decodeUrl(final String url) {
if (url == null) {
return null;
}
try {
return URLDecoder.decode(url, "UTF-8");
} catch (final UnsupportedEncodingException e) {
return url;
}
}
/**
* Encodes the url
*/
public static String encodeUrl(final String url) {
if (url == null) {
return null;
}
try {
return URLEncoder.encode(url, "UTF-8");
} catch (final UnsupportedEncodingException e) {
return url;
}
}
/**
* Returns whether the given string has at least one digit
*/
public static boolean hasDigits(final String string) {
return StringUtils.containsAny(string, DIGITS);
}
/**
* Returns whether the given string has at least one ASCII letter
*/
public static boolean hasLetters(final String string) {
return StringUtils.containsAny(string, LETTERS);
}
/**
* Returns whether the given string has at least one special character (nor digit, nor ASCII letter)
*/
public static boolean hasSpecial(final String string) {
final int length = string == null ? 0 : string.length();
if (length == 0) {
return false;
}
for (int i = 0; i < length; i++) {
final char c = string.charAt(i);
if (LETTERS.indexOf(c) < 0 && DIGITS.indexOf(c) < 0) {
return true;
}
}
return false;
}
/**
* Check if the string is a valid Java identifier. It's not checked if the string is a reserved Java word.
*/
public static boolean isValidJavaIdentifier(final String string) {
if (StringUtils.isEmpty(string)) {
return false;
}
if (!Character.isJavaIdentifierStart(string.charAt(0))) {
return false;
}
for (int i = 1; i < string.length(); i++) {
if (!Character.isJavaIdentifierPart(string.charAt(i))) {
return false;
}
}
return true;
}
/**
* Returns a string containing only the numbers in the given string, or null if input is null
*/
public static String onlyNumbers(final String string) {
if (string == null) {
return null;
}
final StringBuilder numbers = new StringBuilder();
for (int i = 0; i < string.length(); i++) {
final char c = string.charAt(i);
if (Character.isDigit(c)) {
numbers.append(c);
}
}
return numbers.toString();
}
/**
* Removes the CR (Window) characters from the text
* @param text
*/
public static String removeCarriageReturnCharater(final String text) {
return StringUtils.replace(text, "\r\n", "\n");
}
/**
* Removes all html/xml tags
*/
public static String removeMarkupTags(final String string) {
return removeMarkupTagsAndUnescapeEntities(string, false);
}
/**
* Removes all html/xml tags and entities
*/
public static String removeMarkupTagsAndUnescapeEntities(final String string) {
return removeMarkupTagsAndUnescapeEntities(string, true);
}
/**
* Removes the given mask from the given value, trimming to mask length
*/
public static String removeMask(final String mask, final String value) {
return removeMask(mask, value, true);
}
/**
* Removes the given mask from the given value, optionally trimming at mask max length (ex: mask is ###, 12345 would result 123 it true, and 12345
* if false)
*/
public static String removeMask(final String mask, final String value, final boolean trimToMask) {
if (StringUtils.isEmpty(mask) || value == null) {
return value;
}
final StringBuilder sb = new StringBuilder();
boolean nextIsLiteral = false;
int pos = 0;
for (int i = 0; i < mask.length(); i++) {
final char c = mask.charAt(i);
if (c == '\\') {
nextIsLiteral = true;
} else if (!nextIsLiteral && MASK_VARIABLES.indexOf(c) >= 0) {
try {
while (!Character.isLetterOrDigit(value.charAt(pos))) {
pos++;
}
sb.append(value.charAt(pos++));
} catch (final StringIndexOutOfBoundsException e) {
break;
}
} else if (nextIsLiteral) {
nextIsLiteral = false;
sb.append(c);
pos++;
}
}
if (!trimToMask) {
sb.append(value.substring(pos));
}
return sb.toString();
}
/**
* Remove a variable from a query string
*/
public static String removeQueryStringVariable(String queryString, final String var) {
final int pos = queryString.indexOf(var + "=");
if (pos >= 0) {
int end = queryString.indexOf('&', pos);
if (end < 0) {
end = queryString.length();
}
queryString = queryString.substring(0, pos) + queryString.substring(end);
}
return queryString;
}
/**
* Replaces supplementary characters with a ? character
* @param text
* @return
*/
public static String replaceSupplementaryCharacters(final String text) {
if (text == null) {
return null;
}
final int len = text.length();
boolean isSupplementary = false;
final StringBuilder result = new StringBuilder();
for (int i = 0; i < len; i++) {
final int cp = Character.codePointAt(text, i);
isSupplementary = Character.isSupplementaryCodePoint(cp);
if (isSupplementary) {
result.append("?");
i++;
} else {
result.append(text.charAt(i));
}
}
return result.toString();
}
/**
* Transforms the given string into upper case, adding underscores between words. Examples:
* <ul>
* <li>upcase(null) == null</li>
* <li>upcase("") == ""</li>
* <li>upcase("myName") == "MY_NAME"</li>
* <li>upcase("MyName") == "MY_NAME"</li>
* <li>upcase("MyNAME") == "MY_N_A_M_E"</li>
* </ul>
*/
public static String upcase(final String string) {
if (string == null) {
return null;
}
final StringBuilder sb = new StringBuilder(string.length());
for (int i = 0; i < string.length(); i++) {
final char c = string.charAt(i);
if (i > 0 && Character.isUpperCase(c)) {
sb.append('_');
sb.append(c);
} else {
sb.append(Character.toUpperCase(c));
}
}
return sb.toString();
}
private static String removeMarkupTagsAndUnescapeEntities(String string, final boolean unescapeEntities) {
if (string == null) {
return null;
}
final StringBuilder sb = new StringBuilder();
final int length = string.length();
boolean inTag = false;
boolean inComments = false;
boolean hasText = false;
for (int i = 0; i < length; i++) {
final char c = string.charAt(i);
if (c == '<' && i < length - 1 && (Character.isLetterOrDigit(string.charAt(i + 1)) || string.charAt(i + 1) == '/')) {
inTag = true;
} else if (i < length - 4 && "<!--".equals(string.substring(i, i + 4))) {
inComments = true;
i += 3;
} else if (inComments && i < length - 3 && "-->".equals(string.substring(i, i + 3))) {
inComments = false;
hasText = false;
i += 2;
} else if (c == '>') {
inTag = false;
hasText = false;
} else if (!inTag && !inComments) {
if (!hasText) {
// Append an space if this is the first text right after a tag
hasText = true;
if (sb.length() > 0) {
// But not before the first output character
sb.append(' ');
}
}
sb.append(c);
}
}
string = sb.toString();
if (unescapeEntities) {
string = StringEscapeUtils.unescapeHtml(string);
}
return string;
}
}