/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotoolkit.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.geotoolkit.gui.swing.tree.Trees;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ArraysExt;
/**
*
* @author Cédric Briançon (Geomatys)
* @author Guilhem Legal (Geomatys)
*
* @since 3.07
*/
public final class StringUtilities {
public static final String TREE_BLANK = "\u00A0\u00A0\u00A0\u00A0";
public static final String TREE_LINE = "\u00A0\u00A0\u2502\u00A0";
public static final String TREE_CROSS = "\u00A0\u00A0\u251C\u2500";
public static final String TREE_END = "\u00A0\u00A0\u2514\u2500";
private static final int[] EMPTY_INT_ARRAY = new int[0];
private StringUtilities() {}
/**
* Encode the specified string with MD5 algorithm.
*
* @param key : the string to encode.
* @return the value (string) hexadecimal on 32 bits
*/
public static String MD5encode(final String key) {
final byte[] uniqueKey = key.getBytes();
byte[] hash = null;
try {
// we get an object allowing to crypt the string
hash = MessageDigest.getInstance("MD5").digest(uniqueKey);
} catch (NoSuchAlgorithmException e) {
throw new Error("no MD5 support in this VM");
}
final StringBuffer hashString = new StringBuffer();
for (int i = 0; i < hash.length; ++i) {
final String hex = Integer.toHexString(hash[i]);
if (hex.length() == 1) {
hashString.append('0');
hashString.append(hex.charAt(hex.length() - 1));
} else {
hashString.append(hex.substring(hex.length() - 2));
}
}
return hashString.toString();
}
/**
* Clean a string from its leading and trailing whitespaces, and the tabulation or end of line
* characters.
*
* @param s
* @return
*/
public static String clean(String s) {
s = s.trim();
s = s.replace("\t", "");
s = s.replace("\n", "");
s = s.replace("\r", "");
return s;
}
/**
* Clean a list of String by removing all the white space, tabulation and carriage in all the strings.
*
* @param list
* @return
*/
public static List<String> cleanCharSequences(final List<String> list) {
final List<String> result = new ArrayList<String>();
for (String s : list) {
//we remove the bad character before the real value
s = s.replace(" ", "");
s = s.replace("\t", "");
s = s.replace("\n", "");
result.add(s);
}
return result;
}
/**
* Returns true if the list contains a string in one of the list elements.
* This test is not case sensitive.
*
* @see org.apache.sis.util.ArraysExt#containsIgnoreCase(String[], String)
*
* @param list A list of String.
* @param str The value searched.
* @return
*/
public static boolean containsIgnoreCase(final List<String> list, final String str) {
boolean strAvailable = false;
if (list != null) {
for (String s : list) {
if (s.equalsIgnoreCase(str)) {
strAvailable = true;
break;
}
}
}
return strAvailable;
}
/**
* Generate a {@code String} whose first character will be in upper case.
* <p>
* For example: {@code firstToUpper("hello")} would return {@code "Hello"},
* while {@code firstToUpper("Hi!") would return {@code "Hi!"} unchanged.
*
* @param s The {@code String} to evaluate, not {@code null}.
*
* @return A {@code String} with the first character in upper case.
*/
public static String firstToUpper(final String s) {
if (s != null && !s.isEmpty()) {
final String first = s.substring(0, 1);
String result = s.substring(1);
result = first.toUpperCase() + result;
return result;
}
return s;
}
/**
* Search a string for all occurence of the char.
*
* @param s : String to search in
* @param occ : Occurence to search
* @return array of all occurence indexes
*/
public static int[] getIndexes(final String s, final char occ) {
int pos = s.indexOf(occ);
if(pos <0){
return EMPTY_INT_ARRAY;
}else{
int[] indexes = new int[]{pos};
pos = s.indexOf(occ, pos+1);
for(; pos >= 0; pos = s.indexOf(occ, pos+1)){
int end = indexes.length;
indexes = ArraysExt.resize(indexes, end+1);
indexes[end] = pos;
}
return indexes;
}
}
/**
* Convert the given string into a string recognize by HTML.
*
* @param text The string to convert.
* @return The string wit no special chars, which are not recognized in HTML.
*/
public static String htmlEncodeSpecialChars(final String text) {
final StringBuilder sb = new StringBuilder();
for (int i=0; i<text.length(); i++) {
final char c = text.charAt(i);
if (c > 127) { // special chars
sb.append("").append((int)c).append(";");
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* Returns true if one of the {@code String} elements in a {@code List}
* matches the given {@code String}, insensitive to case.
*
* @param list A {@code List<String>} with elements to be tested.
* @param str The {@code String} to evaluate.
*
* @return {@code true}, if at least one element of the list matches the
* parameter, {@code false} otherwise.
*/
public static boolean matchesStringfromList(final List<String> list,final String str) {
boolean strAvailable = false;
for (String s : list) {
final Pattern pattern = Pattern.compile(str,Pattern.CASE_INSENSITIVE | Pattern.CANON_EQ);
final Matcher matcher = pattern.matcher(s);
if (matcher.find()) {
strAvailable = true;
}
}
return strAvailable;
}
/**
* Replace all the <ns**:localPart and </ns**:localPart by <prefix:localPart and </prefix:localPart>
*
* @param s
* @param localPart
* @return
*/
public static String replacePrefix(final String s, final String localPart, final String prefix) {
return s.replaceAll("[a-zA-Z0-9]*:" + localPart, prefix + ":" + localPart);
}
/**
* Remove all the XML namespace declaration.
* @param xml
* @return
*/
public static String removeXmlns(final String xml) {
String s = xml;
s = s.replaceAll("xmlns=\"[^\"]*\" ", "");
s = s.replaceAll("xmlns=\"[^\"]*\"", "");
s = s.replaceAll("xmlns:[^=]*=\"[^\"]*\" ", "");
s = s.replaceAll("xmlns:[^=]*=\"[^\"]*\"", "");
return s;
}
/**
* Remove the prefix on propertyName.
* example : removePrefix(csw:GetRecords) return "GetRecords".
*/
public static String removePrefix(String s) {
final int i = s.indexOf(':');
if ( i != -1) {
s = s.substring(i + 1, s.length());
}
return s;
}
/**
* Returns the values of the list separated by commas.
*
* @param values The collection to extract values.
* @return A string which contains values concatened with comma(s), or an empty
* string if the list is empty or {@code null}.
*/
public static String toCommaSeparatedValues(final Collection<?> values) {
if (values == null || values.isEmpty()) {
return "";
}
final StringBuilder builder = new StringBuilder();
boolean first = true;
for(Object obj : values){
if(first){
first = false;
}else{
builder.append(',');
}
builder.append(obj);
}
return builder.toString();
}
/**
* Returns the values of the array separated by commas.
*
* @param values The array to extract values.
* @return A string which contains values concatened with comma(s), or an empty
* string if the array is empty or {@code null}.
*/
public static String toCommaSeparatedValues(final Object ... values) {
if (values == null || values.length == 0) {
return "";
}
final StringBuilder builder = new StringBuilder();
final int size = values.length;
for (int i=0; i<size; i++) {
if (i>0) {
builder.append(',');
}
builder.append(values[i]);
}
return builder.toString();
}
/**
* Split a string on commas, and return it as a list.
*
* @param commaSeparatedString A string which contains comma(s).
* @return A list of elements that were contained in the string separated by comma(s).
*/
public static List<String> toStringList(final String commaSeparatedString) {
return toStringList(commaSeparatedString, ',');
}
/**
* Split a string on a special character, and return it as a list.
*
* @param toSplit A string to split on a specific character.
* @param separator The special character on which the given string will be splitted.
* @return A list of elements that were contained in the string separated by the special
* character.
*
* @deprecated Replaced by {@link org.apache.sis.util.CharSequences#split(CharSequence, char)}.
*/
@Deprecated
public static List<String> toStringList(String toSplit, final char separator) {
if (toSplit == null) {
return Collections.emptyList();
}
final List<String> strings = new ArrayList<>();
int last = 0;
toSplit = toSplit.trim();
for (int i=toSplit.indexOf(separator); i>=0; i=toSplit.indexOf(separator, i)) {
strings.add(toSplit.substring(last, i).trim());
last = ++i;
}
strings.add(toSplit.substring(last).trim());
return strings;
}
/**
* Formats the given elements as a (typically) comma-separated list. This method is similar to
* {@link java.util.AbstractCollection#toString()} or {@link java.util.Arrays#toString(Object[])}
* except for the following:
*
* <ul>
* <li>There is no leading {@code '['} or trailing {@code ']'} characters.</li>
* <li>Null elements are ignored instead than formatted as {@code "null"}.</li>
* <li>If the {@code collection} argument is null or contains only null elements,
* then this method returns {@code null}.</li>
* <li>In the common case where the collection contains a single {@link String} element,
* that string is returned directly (no object duplication).</li>
* </ul>
*
* @param collection The elements to format in a (typically) comma-separated list, or {@code null}.
* @param separator The element separator, which is usually {@code ", "}.
* @return The (typically) comma-separated list, or {@code null} if the given {@code collection}
* was null or contains only null elements.
*
* @see java.util.StringJoiner
* @see java.util.Arrays#toString(Object[])
*/
public static String toString(final Iterable<?> collection, final String separator) {
ArgumentChecks.ensureNonNull("separator", separator);
String list = null;
if (collection != null) {
StringBuilder buffer = null;
for (final Object element : collection) {
if (element != null) {
if (list == null) {
list = element.toString();
} else {
if (buffer == null) {
buffer = new StringBuilder(list);
}
buffer.append(separator);
if (element instanceof CharSequence) {
// StringBuilder has numerous optimizations for this case.
buffer.append((CharSequence) element);
} else {
buffer.append(element);
}
}
}
}
if (buffer != null) {
list = buffer.toString();
}
}
return list;
}
/**
* Transform an exception code into the OWS specification.
* Example : MISSING_PARAMETER_VALUE become MissingParameterValue.
*
* @param code
* @return
*/
public static String transformCodeName(String code) {
final StringBuilder result = new StringBuilder();
while (code.indexOf('_') != -1) {
final String tmp = code.substring(0, code.indexOf('_')).toLowerCase();
result.append(firstToUpper(tmp));
code = code.substring(code.indexOf('_') + 1, code.length());
}
code = code.toLowerCase();
result.append(firstToUpper(code));
return result.toString();
}
public static String toStringTree(final Object ... objects){
return Trees.toString("", Arrays.asList(objects));
}
}