/* * Copyright (C) 2009-2010 Open Wide * Contact: contact@openwide.fr * * Large portions Copyright Apache Software Foundation * * Licensed 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 fr.openwide.core.spring.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.regex.Pattern; import org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.RamUsageEstimator; import com.google.common.base.CharMatcher; /** * <p>Utilitaire permettant de manipuler les chaînes de caractères.</p> * * <p>Il permet de wrapper des méthodes des StringUtils de Spring et des * StringUtils de commons-lang et ajoute par ailleurs quelques méthodes * complémentaires dont le removeAccents qui provient de Lucene.</p> * * @author Open Wide */ public final class StringUtils extends org.springframework.util.StringUtils { public static final String CHARSET_ISO_8859_1 = "ISO-8859-1"; public static final String CHARSET_UTF_8 = "UTF-8"; public static final char SPACE_CHAR = ' '; public static final String SPACE = " "; public static final char DASH_CHAR = '-'; public static final String DASH = "-"; public static final String ASTERISK = "*"; public static final char ASTERISK_CHAR = '*'; public static final Pattern CLEAN_SPECIAL_CHARS_REGEXP_PATTERN = Pattern.compile("[^a-z0-9-]"); public static final Pattern CLEAN_SPECIAL_CHARS_QUERY_REGEXP_PATTERN = Pattern.compile("[^a-z0-9-*]"); public static final Pattern CLEAN_DUPLICATE_DASHES_REGEXP_PATTERN = Pattern.compile("--*"); public static final Pattern CLEAN_DUPLICATE_SPACES_REGEXP_PATTERN = Pattern.compile(" *"); public static final Pattern CLEAN_DUPLICATE_ASTERISKS_REGEXP_PATTERN = Pattern.compile("\\*\\**"); public static final Pattern TAGIFY_REGEXP_PATTERN = Pattern.compile("[^a-z0-9.]"); public static final String COLLECTION_DEFAULT_DELIMITER = ", "; public static final String NEW_LINE_ANTISLASH_N = "\n"; public static final String NEW_LINE_ANTISLASH_R = "\r"; public static final String NEW_LINE_ANTISLASH_R_ANTISLASH_N = NEW_LINE_ANTISLASH_R + NEW_LINE_ANTISLASH_N; /** * @see org.apache.commons.lang3.StringUtils#replaceEach(String, String[],String[]) */ public static String replaceEach(String text, String[] searchList, String[] replacementList) { return org.apache.commons.lang3.StringUtils.replaceEach(text, searchList, replacementList); } /** * @see org.apache.commons.lang3.StringUtils#join(Object[], String) */ public static String join(String[] array, String separator) { return org.apache.commons.lang3.StringUtils.join(array, separator); } /** * @see org.apache.commons.lang3.StringUtils#join(java.util.Collection,String) */ public static String join(Collection<String> collection, String separator) { return org.apache.commons.lang3.StringUtils.join(collection, separator); } public static List<String> splitAsList(String str, String separatorChar) { return new ArrayList<String>(Arrays.asList(delimitedListToStringArray(str, separatorChar))); } /** * @see org.apache.commons.lang3.StringUtils#capitalize(String) */ public static String capitalize(String str) { return org.apache.commons.lang3.StringUtils.capitalize(str); } /** * @see org.apache.commons.lang3.StringUtils#lowerCase(String) */ public static String lowerCase(String str) { return org.apache.commons.lang3.StringUtils.lowerCase(str); } /** * @see org.apache.commons.lang3.StringUtils#upperCase(String) */ public static String upperCase(String str) { return org.apache.commons.lang3.StringUtils.upperCase(str); } /** * @see org.apache.commons.lang3.StringUtils#contains(String, String) */ public static boolean contains(String str, String searchStr) { return org.apache.commons.lang3.StringUtils.contains(str, searchStr); } /** * @see org.apache.commons.lang3.StringUtils#substring(String, int, int) */ public static String substring(String str, int start, int end) { return org.apache.commons.lang3.StringUtils.substring(str, start, end); } /** * @see org.apache.commons.lang3.StringUtils#isNumeric(String) */ public static boolean isNumeric(String str) { return org.apache.commons.lang3.StringUtils.isNumeric(str); } /** * @see org.apache.commons.lang3.StringUtils#rightPad(String, int, char) */ public static String rightPad(String str, int size, char padChar) { return org.apache.commons.lang3.StringUtils.rightPad(str, size, padChar); } /** * @see org.apache.commons.lang3.StringUtils#leftPad(String, int, char) */ public static String leftPad(String str, int size, char padChar) { return org.apache.commons.lang3.StringUtils.leftPad(str, size, padChar); } /** * Supprime les caractères spéciaux d'une chaîne de caractères et retourne une chaîne utilisable dans une URL. * * @param strToClean chaîne à nettoyer * @return chaîne nettoyée */ public static String urlize(String strToClean) { return sanitizeString(strToClean, CLEAN_SPECIAL_CHARS_REGEXP_PATTERN); } /** * Supprime les caractères spéciaux d'une chaîne de caractères et retourne une chaîne utilisable pour un tag. * * La grande différence par rapport à une URL est qu'on autorise les ".", notamment pour pouvoir définir des numéros de version. * * @param strToClean chaîne à nettoyer * @return chaîne nettoyée */ public static String tagify(String strToClean) { return sanitizeString(strToClean, TAGIFY_REGEXP_PATTERN); } private static String sanitizeString(String strToClean, Pattern cleanRegexpPattern) { if (strToClean == null) { return null; } String str = strToClean.trim(); str = StringUtils.removeAccents(str); str = StringUtils.lowerCase(str); str = cleanRegexpPattern.matcher(str).replaceAll(DASH); str = CLEAN_DUPLICATE_DASHES_REGEXP_PATTERN.matcher(str).replaceAll(DASH); str = org.apache.commons.lang3.StringUtils.strip(str, DASH); return str; } /** * Nettoie une chaîne de caractères en conservant les espaces * * @param strToClean chaîne à nettoyer * @return chaîne nettoyée */ public static String clean(String strToClean) { return clean(strToClean, CLEAN_SPECIAL_CHARS_REGEXP_PATTERN); } /** * Nettoie une chaîne de caractères qui part à destination d'une recherche Lucene. On souhaite autoriser le fait * qu'il puisse y avoir un wildcard. */ public static String cleanForQuery(String strToClean) { return clean(strToClean, CLEAN_SPECIAL_CHARS_QUERY_REGEXP_PATTERN); } private static String clean(String strToClean, Pattern forbiddenCharactersPattern) { if (strToClean == null) { return null; } String str = strToClean.trim(); str = StringUtils.removeAccents(str); str = StringUtils.lowerCase(str); str = forbiddenCharactersPattern.matcher(str).replaceAll(SPACE); str = CLEAN_DUPLICATE_SPACES_REGEXP_PATTERN.matcher(str).replaceAll(SPACE); str = CLEAN_DUPLICATE_ASTERISKS_REGEXP_PATTERN.matcher(str).replaceAll(ASTERISK); str = org.apache.commons.lang3.StringUtils.strip(str, SPACE + DASH); return str; } /** * Supprime les accents d'une chaîne de caractères. * * @param text chaîne à nettoyer * @return chaîne sans accent * @see org.apache.lucene.analysis.ASCIIFoldingFilter */ public static String removeAccents(String text) { if (text == null) { return text; } int length = text.length(); char[] input = text.toCharArray(); char[] output = new char[256]; // Worst-case length required: final int maxSizeNeeded = 4 * length; if (output.length < maxSizeNeeded) { output = new char[ArrayUtil.oversize(maxSizeNeeded, RamUsageEstimator.NUM_BYTES_CHAR)]; } int outputPos = ASCIIFoldingFilter.foldToASCII(input, 0, output, 0, length); return new String(output, 0, outputPos); } /** * Compare deux chaînes potentiellement nulles. * @param string1 la première chaîne * @param string2 la seconde chaîne * @return résultat de la comparaison */ public static int compare(String string1, String string2) { if (string1 == null) { if (string2 == null) { return 0; } else { return -1; } } if (string2 == null) { return 1; } return string1.compareTo(string2); } /** * Uniformise les retours à la ligne en transformant les <code>\r\n</code> et les <code>\r</code> en <code>\n</code>. * * @param string chaîne à nettoyer * @return chaîne nettoyée */ public static String normalizeNewLines(String string) { if (string == null) { return null; } String cleanString = string.replace(NEW_LINE_ANTISLASH_R_ANTISLASH_N, NEW_LINE_ANTISLASH_N); cleanString = cleanString.replace(NEW_LINE_ANTISLASH_R, NEW_LINE_ANTISLASH_N); return cleanString; } private StringUtils() { } /** * Convertit les bytes en données interprétables * * source : http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java/3758880#3758880 * * @param bytes valeur en bytes * @param si détermine le standard à utiliser (SI ou binary) * @return équivalent en unités SI ou binary */ public static String humanReadableByteCount(long bytes, boolean si) { int unit = si ? 1000 : 1024; if (bytes < unit) return bytes + " B"; int exp = (int) (Math.log(bytes) / Math.log(unit)); String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); } public static String emptyTextToNull(String str) { return hasText(str) ? str : null; } public static String capitalizeFully(String str, CharMatcher charMatcher) { if (str == null) { return null; } str = lowerCase(str); return capitalize(str, charMatcher); } public static String capitalize(String str, CharMatcher charMatcher) { if (str == null) { return null; } final char[] buffer = str.toCharArray(); boolean capitalizeNext = true; for (int i = 0; i < buffer.length; i++) { final char ch = buffer[i]; if (charMatcher.matches(ch)) { capitalizeNext = true; } else if (capitalizeNext) { buffer[i] = Character.toTitleCase(ch); capitalizeNext = false; } } return new String(buffer); } }