Java tutorial
/* * Copyright (c) 2004-2016 YAMJ Members * https://github.com/orgs/YAMJ/people * * This file is part of the Yet Another Movie Jukebox (YAMJ) project. * * YAMJ 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 3 of the License, or * any later version. * * YAMJ 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 YAMJ. If not, see <http://www.gnu.org/licenses/>. * * Web: https://github.com/YAMJ/yamj-v2 * */ package com.moviejukebox.tools; import java.text.BreakIterator; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.moviejukebox.model.Movie; /** * String related tools for the jukebox * * @author Stuart.Boston */ public final class StringTools { private static final Logger LOG = LoggerFactory.getLogger(StringTools.class); private static final Pattern CLEAN_STRING_PATTERN = Pattern.compile("[^a-zA-Z0-9]"); // Number formatting private static final long KB = 1024; private static final long MB = KB * KB; private static final long GB = KB * KB * KB; private static final DecimalFormat FILESIZE_FORMAT_0 = new DecimalFormat("0"); private static final DecimalFormat FILESIZE_FORMAT_1 = new DecimalFormat("0.#"); private static final DecimalFormat FILESIZE_FORMAT_2 = new DecimalFormat("0.##"); private static final Map<Character, Character> CHAR_REPLACEMENT_MAP = new HashMap<>(); // Quote replacements private static final String QUOTE_SINGLE = "\'"; private static final Pattern QUOTE_PATTERN = Pattern.compile(generateQuoteList()); // Literals private static final String MPPA_RATED = "Rated"; private StringTools() { throw new UnsupportedOperationException("Class cannot be instantiated"); } static { // Populate the charReplacementMap StringTokenizer tokenizer = new StringTokenizer( PropertiesUtil.getProperty("indexing.character.replacement", ""), ","); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); int idx = token.indexOf('-'); if (idx > 0) { String key = token.substring(0, idx).trim(); String value = token.substring(idx + 1).trim(); if (key.length() == 1 && value.length() == 1) { CHAR_REPLACEMENT_MAP.put(key.charAt(0), value.charAt(0)); } } } } /** * Generate the pattern string for all available quote marks * * @return */ private static String generateQuoteList() { Set<String> quotes = new HashSet<>(); // Double quote - " quotes.add("\""); // Single left quote - quotes.add("\u2018"); // Single right quote - quotes.add("\u2019"); // Double left quote - quotes.add("\u201C"); // Double right quote - ? quotes.add("\u201D"); // Low single quote - quotes.add("\u201A"); // Low double quote - quotes.add("\u201E"); // Backtick "quote" - ` quotes.add("`"); // Odd quote character that comes across from TheTVDB quotes.add(""); // Add the XML version of ' quotes.add("'"); StringBuilder quoteString = new StringBuilder(); for (String quote : quotes) { quoteString.append(quote).append("|"); } quoteString.deleteCharAt(quoteString.length() - 1); return quoteString.toString(); } /** * Check the passed character against the replacement list. * * @param charToReplace * @return */ public static String characterMapReplacement(Character charToReplace) { Character tempC = CHAR_REPLACEMENT_MAP.get(charToReplace); if (tempC == null) { return charToReplace.toString(); } return tempC.toString(); } /** * Change all the characters in a string to the safe replacements * * @param stringToReplace * @return */ public static String stringMapReplacement(String stringToReplace) { Character tempC; StringBuilder sb = new StringBuilder(); for (Character c : stringToReplace.toCharArray()) { tempC = CHAR_REPLACEMENT_MAP.get(c); if (tempC == null) { sb.append(c); } else { sb.append(tempC); } } return sb.toString(); } /** * Append a string to the end of a path ensuring that there are the correct * number of File.separators * * @param basePath * @param additionalPath * @return */ public static String appendToPath(final String basePath, final String additionalPath) { String tmpAdditionalPath; if (additionalPath.startsWith("\\") || additionalPath.startsWith("/")) { // Remove any path characters from the additional path as this interferes with the conncat tmpAdditionalPath = additionalPath.substring(1); } else { tmpAdditionalPath = additionalPath; } return FilenameUtils.concat(basePath, tmpAdditionalPath); } /** * Strip all non-alphanumeric characters from a string replacing with a * space * * @param sourceString * @return */ public static String cleanString(String sourceString) { return CLEAN_STRING_PATTERN.matcher(sourceString).replaceAll(" ").trim(); } /** * Format the file size * * @param fileSize * @return */ public static String formatFileSize(long fileSize) { String returnSize; if (fileSize < KB) { returnSize = fileSize + " Bytes"; } else { String appendText; long divider; // resolve text to append and divider if (fileSize < MB) { appendText = " KB"; divider = KB; } else if (fileSize < GB) { appendText = " MB"; divider = MB; } else { appendText = " GB"; divider = GB; } // resolve decimal format DecimalFormat df; long checker = (fileSize / divider); if (checker < 10) { df = FILESIZE_FORMAT_2; } else if (checker < 100) { df = FILESIZE_FORMAT_1; } else { df = FILESIZE_FORMAT_0; } // build string returnSize = df.format(((float) fileSize / (float) divider)) + appendText; } return returnSize; } /** * Check the string passed to see if it is invalid. Invalid strings are * "UNKNOWN", null or blank * * @param testString The string to test * @return True if the string is invalid, Boolean.FALSE otherwise */ public static boolean isNotValidString(String testString) { return !isValidString(testString); } /** * Check the string passed to see if it contains a value. * * @param testString The string to test * @return False if the string is empty, null or UNKNOWN, True otherwise */ public static boolean isValidString(String testString) { // Checks if a String is whitespace, empty ("") or null. if (StringUtils.isBlank(testString)) { return Boolean.FALSE; } if (testString.equalsIgnoreCase(Movie.UNKNOWN)) { return Boolean.FALSE; } return Boolean.TRUE; } /** * Check that the passed string is not longer than the required length and * trim it if necessary. * * @param sourceString * @param requiredLength * @return */ public static String trimToLength(String sourceString, int requiredLength) { return trimToLength(sourceString, requiredLength, Boolean.TRUE, "..."); } /** * Check that the passed string is not longer than the required length and * trim it if necessary * * @param sourceString The string to check * @param requiredLength The required length (Maximum) * @param trimToWord Trim the source string to the last space to avoid * partial words * @param endingSuffix The ending to append if the string is longer than the * required length * @return */ public static String trimToLength(String sourceString, int requiredLength, boolean trimToWord, String endingSuffix) { String changedString = sourceString.trim(); if (isValidString(changedString)) { if (changedString.length() <= requiredLength) { // No need to do anything return changedString; } if (trimToWord) { BreakIterator bi = BreakIterator.getWordInstance(); bi.setText(changedString); int biLength = bi.preceding(requiredLength - endingSuffix.length() + 1); return changedString.substring(0, biLength).trim() + endingSuffix; } // We know that the source string is longer that the required length, so trim it to size return changedString.substring(0, requiredLength - endingSuffix.length()).trim() + endingSuffix; } return changedString; } /** * Cast a generic list to a specific class * * See: * http://stackoverflow.com/questions/367626/how-do-i-fix-the-expression-of-type-list-needs-unchecked-conversion * * @param <T> * @param objClass * @param c * @return */ public static <T> List<T> castList(Class<? extends T> objClass, Collection<?> c) { List<T> r = new ArrayList<>(c.size()); for (Object o : c) { r.add(objClass.cast(o)); } return r; } /** * Split a list using a regex and return a list of trimmed strings * * @param stringToSplit * @param regexDelim * @return */ public static List<String> splitList(String stringToSplit, String regexDelim) { List<String> finalValues = new ArrayList<>(); for (String output : stringToSplit.split(regexDelim)) { finalValues.add(output.trim()); } return finalValues; } public static String[] tokenizeToArray(String sourceString, String delimiter) { StringTokenizer st = new StringTokenizer(sourceString, delimiter); Collection<String> keywords = new ArrayList<>(); while (st.hasMoreTokens()) { keywords.add(st.nextToken()); } return keywords.toArray(new String[keywords.size()]); } /** * Get the certification from the MPAA string * * @param mpaaCertification * @return */ public static String processMpaaCertification(String mpaaCertification) { return processMpaaCertification(MPPA_RATED, mpaaCertification); } /** * Get the certification from the MPAA rating string * * @param mpaaRated * @param mpaaCertification * @return */ public static String processMpaaCertification(String mpaaRated, String mpaaCertification) { // Strip out the "Rated " and extra words at the end of the MPAA certification Pattern mpaaPattern = Pattern .compile("(?:" + (isValidString(mpaaRated) ? mpaaRated : MPPA_RATED) + "\\s)?(.*?)(?:($|\\s).*?)"); Matcher m = mpaaPattern.matcher(mpaaCertification); if (m.find()) { return m.group(1).trim(); } return mpaaCertification.trim(); } /** * Replace all the non-standard quote marks with a single quote * * @param original * @return */ public static String replaceQuotes(String original) { return QUOTE_PATTERN.matcher(original).replaceAll(QUOTE_SINGLE); } /** * Parse a string value and convert it into an integer rating * * The rating should be between 0 and 10 inclusive.<br/> * Invalid values or values less than 0 will return -1 * * @param rating the converted rating or -1 if there was an error * @return */ public static int parseRating(String rating) { return parseRating(NumberUtils.toFloat(rating.replace(',', '.'), -1)); } /** * Parse a float rating into an integer * * The rating should be between 0 and 10 inclusive.<br/> * Invalid values or values less than 0 will return -1 * * @param rating the converted rating or -1 if there was an error * @return */ public static int parseRating(float rating) { float tmp; if (rating < 0) { return -1; } else if (rating > 10f) { tmp = 10; } else { tmp = rating; } return Math.round(tmp * 10f); } /** * Trim a string to the 'n'th occurrence of a space. * * @param sentanceToTrim * @param numOfWords * @return */ public static String getWords(final String sentanceToTrim, int numOfWords) { String returnSentance = sentanceToTrim; // count the number of spaces in the original string int numSpaces = StringUtils.countMatches(sentanceToTrim, " "); LOG.trace("Found {} space(s) in '{}', want {} word(s).", numSpaces, sentanceToTrim, numOfWords); if (numSpaces > 0 && numSpaces >= numOfWords) { // ensure that the number of spaces is no larger than the count if (numSpaces > numOfWords) { LOG.trace("Number of spaces limited to {}", numOfWords); numSpaces = numOfWords; } int pos = -1; for (int i = 1; i <= numSpaces; i++) { pos = sentanceToTrim.indexOf(' ', pos + 1); } returnSentance = sentanceToTrim.substring(0, pos); LOG.trace("Final: '{}'", returnSentance); } return returnSentance; } }