/* * Eoulsan development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public License version 2.1 or * later and CeCILL-C. This should be distributed with the code. * If you do not have a copy, see: * * http://www.gnu.org/licenses/lgpl-2.1.txt * http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt * * Copyright for this code is held jointly by the Genomic platform * of the Institut de Biologie de l'École normale supérieure and * the individual authors. These should be listed in @author doc * comments. * * For more information on the Eoulsan project and its aims, * or to join the Eoulsan Google group, visit the home page * at: * * http://outils.genomique.biologie.ens.fr/eoulsan * */ package fr.ens.biologie.genomique.eoulsan.util; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; /** * Utility class for Strings. * @since 1.0 * @author Laurent Jourdren */ public final class StringUtils { /** * Get the basename of the filename. * @param filename The filename * @return the basename of the file */ public static String basename(final String filename) { return basename(filename, true); } /** * Get the basename of the filename. * @param filename The filename * @param withoutCompressedExtension true if the compression extension must be * removed * @return the basename of the file */ public static String basename(final String filename, final boolean withoutCompressedExtension) { if (filename == null) { return null; } final String myFilename; if (withoutCompressedExtension) { myFilename = removeCompressedExtensionFromFilename(filename); } else { myFilename = filename; } final File f = new File(myFilename); final String shortName = f.getName(); final int pos = shortName.indexOf('.'); if (pos == -1) { return myFilename; } return myFilename.substring(0, myFilename.length() - (shortName.length() - pos)); } /** * Get the extension of a filename. * @param filename The filename * @return the extension of the filename */ public static String extension(final String filename) { if (filename == null) { return null; } final File f = new File(filename); final String shortName = f.getName(); final int pos = shortName.lastIndexOf('.'); if (pos == -1) { return ""; } return filename.substring(filename.length() - (shortName.length() - pos), filename.length()); } /** * Get the extension without compression extension * @param filename The filename * @return the extension without the compression extension */ public static String extensionWithoutCompressionExtension( final String filename) { return extension(filenameWithoutCompressionExtension(filename)); } /** * Get the filename without the extension. * @param filename The filename * @return the filename without the extension */ public static String filenameWithoutExtension(final String filename) { if (filename == null) { return null; } final File f = new File(filename); final String shortName = f.getName(); final int pos = shortName.lastIndexOf('.'); if (pos == -1) { return filename; } return filename.substring(0, filename.length() - shortName.length()) + shortName.subSequence(0, pos); } /** * Get the compression extension if exists. * @param filename The filename * @return the compression extension or an empty string if there is no * compression extension */ public static String compressionExtension(final String filename) { if (filename == null) { return null; } final String ext = extension(filename); if (".gz".equals(ext)) { return ext; } if (".bz2".equals(ext)) { return ext; } if (".zip".equals(ext)) { return ext; } if (".deflate".equals(ext)) { return ext; } if (".lzo".equals(ext)) { return ext; } return ""; } /** * Get the filename without the compression extension. * @param filename The filename * @return the filename without the compression extension */ public static String filenameWithoutCompressionExtension( final String filename) { if (filename == null) { return null; } if (filename.endsWith(".gz")) { return filename.substring(0, filename.length() - 3); } if (filename.endsWith(".bz2")) { return filename.substring(0, filename.length() - 4); } // if (filename.endsWith(".zip")) // return filename.substring(0, filename.length() - 4); if (filename.endsWith(".deflate")) { return filename.substring(0, filename.length() - 8); } if (filename.endsWith(".lzo")) { return filename.substring(0, filename.length() - 4); } return filename; } /** * Remove non alpha char at the end of String. * @param s String to handle * @return the string without the last non end of string */ public static final String removeNonAlphaAtEndOfString(final String s) { if (s == null) { return null; } int len = s.length(); if (len == 0) { return s; } char c = s.charAt(len - 1); if (!Character.isLetter(c)) { return s.substring(0, len - 1); } return s; } /** * Convert a number of milliseconds into a human reading string. * @param time time in ms * @return a the time in ms */ public static final String toTimeHumanReadable(final long time) { long min = time / (60 * 1000); long minRest = time % (60 * 1000); long sec = minRest / 1000; long mili = minRest % 1000; return String.format("%02d:%02d.%03d", min, sec, mili); } /** * Convert a number of milliseconds into a human reading string. * @param millisSinceEpoch time in ms * @return a string with the compact time */ public static final String toCompactTime(final long millisSinceEpoch) { final Calendar cal = Calendar.getInstance(Locale.ENGLISH); cal.setTime(new Date(millisSinceEpoch)); return String.format("%04d%02d%02d-%02d%02d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND)); } /** * Split a string. \t is the separator character. * @param s the String to split * @param list The result list. * @return the array with the new values */ public static final List<String> fastSplit(final String s, final List<String> list) { if (s == null) { return null; } List<String> result; if (list == null) { result = new ArrayList<>(); } else { result = list; } result.clear(); int lastPos = 0; int pos = -1; while ((pos = s.indexOf("\t", lastPos)) != -1) { result.add(s.substring(lastPos, pos)); lastPos = pos + 1; } result.add(s.substring(lastPos, s.length())); return result; } /** * Split a string. \t is the separator character. * @param s the String to split * @param array The result array. * @return the array with the new values */ public static final String[] fastSplit(final String s, final String[] array) { return fastSplit(s, array, false); } /** * Split a string. \t is the separator character. * @param s the String to split * @param array The result array. * @param allowEmptyFields to allow empty fields * @return the array with the new values */ public static final String[] fastSplit(final String s, final String[] array, final boolean allowEmptyFields) { if (array == null || s == null) { return null; } int lastPos = 0; final int len = array.length - 1; for (int i = 0; i < len; i++) { final int pos = s.indexOf("\t", lastPos); if (pos == -1) { if (allowEmptyFields) { while (i <= len) { array[i++] = ""; } return array; } throw new ArrayIndexOutOfBoundsException(); } array[i] = s.substring(lastPos, pos); lastPos = pos + 1; } array[len] = s.substring(lastPos, s.length()); return array; } /** * Get the content of a line without the first field. Tabulation is the * separator * @param s String to parse * @return a String without the first field of the string */ public static final String subStringAfterFirstTab(final String s) { if (s == null) { return null; } final int indexFirstTab = s.indexOf('\t'); if (indexFirstTab == -1) { return s; } return s.substring(indexFirstTab + 1); } /** * Get the first field of a line * @param s String to parse * @return a String with the first field of the string */ public static final String subStringBeforeFirstTab(final String s) { if (s == null) { return null; } final int indexFirstTab = s.indexOf('\t'); if (indexFirstTab == -1) { return s; } return s.substring(0, indexFirstTab); } /** * Get the current date in an easy sorted format (e.g. 20100225151635) * @return the current date formatted in a string */ public static final String currentDateTimeToEasySortedDateTime() { return toEasySortedDateTime(new Date(System.currentTimeMillis())); } /** * Get the date in an easy sorted format (e.g. 20100225151635) * @param date date to format * @return a formatted date in a string */ public static final String toEasySortedDateTime(final Date date) { if (date == null) { return null; } final Calendar cal = Calendar.getInstance(Locale.ENGLISH); return String.format("%04d%02d%02d%02d%02d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND)); } /** * Remove the compression extension of the filename. * @param filename Filename to use * @return the filename without the compressed extension if needed */ public static final String removeCompressedExtensionFromFilename( final String filename) { if (filename == null) { return null; } if (filename.endsWith(".gz")) { return filename.substring(0, filename.length() - 3); } if (filename.endsWith(".bz2")) { return filename.substring(0, filename.length() - 4); } if (filename.endsWith(".zip")) { return filename.substring(0, filename.length() - 4); } return filename; } public static final String protectGFF(final String s) { if (s == null) { return null; } final String rTmp = s.replace("\\", "\\\\").replace(";", "\\;").replace("=", "\\=") .replace("%", "\\%").replace("&", "\\&").replace(",", "\\,"); final StringBuilder sb = new StringBuilder(); final int len = rTmp.length(); for (int i = 0; i < len; i++) { final char c = rTmp.charAt(i); if (c <= 32) { sb.append('%'); sb.append(String.format("%02X", (int) c)); } else { sb.append(c); } } final String r = sb.toString(); sb.setLength(0); return r; } public static final String deProtectGFF(final String s) { if (s == null) { return null; } final StringBuilder sb = new StringBuilder(); final int len = s.length(); for (int i = 0; i < len; i++) { final char c = s.charAt(i); if (c == '%') { if (i + 2 >= len) { break; } final char d1 = s.charAt(i + 1); final char d2 = s.charAt(i + 2); if (Character.isDigit(d1) && Character.isDigit(d2)) { sb.append((char) Integer.parseInt("" + d1 + d2, 16)); i += 2; continue; } } sb.append(c); } return sb.toString().replace("\\,", ",").replace("\\&", "&") .replace("\\%", "%").replace("\\=", "=").replace("\\;", ";") .replace("\\\\", "\\"); } /** * Get an array without the first element of the input array. * @param array input array * @return an array without the first element of the input array */ public static final String[] arrayWithoutFirstElement(final String[] array) { return arrayWithoutFirstsElement(array, 1); } /** * Get an array without the first element of the input array. * @param array input array * @param elementsToRemove number of the first elements to remove * @return an array without the first element of the input array */ public static final String[] arrayWithoutFirstsElement(final String[] array, final int elementsToRemove) { if (array == null) { return null; } if (elementsToRemove < 1) { return array; } if (elementsToRemove > array.length) { return new String[0]; } final int newLen = array.length - elementsToRemove; final String[] result = new String[newLen]; System.arraycopy(array, elementsToRemove, result, 0, newLen); return result; } /** * Escape a bash filename * @param s bash string to escape * @return a escaped string */ public static final String bashEscaping(final String s) { if (s == null) { return null; } return s.replace("\\", "\\\\").replace(" ", "\\ ").replace("'", "\\'") .replace("\"", "\\\"").replace("&", "\\&").replace("!", "\\!") .replace("~", "\\~"); } /** * Get the filename of an URI * @param s The URI in a string * @return the filename of the URI */ public static final String getURIFilename(final String s) { if (s == null) { return null; } try { final URI uri = new URI(s); return new File(uri.getPath()).getName(); } catch (URISyntaxException e) { return null; } } /** * Get a file size in a human readable way * @param bytes size of a file * @return a string with the size of the file */ public static final String sizeToHumanReadable(final long bytes) { final double ki = 1024; final double mi = ki * 1024; final double gi = mi * 1024; final double ti = gi * 1024; if (bytes < ki) { return String.format("%d B", bytes); } if (bytes < mi) { return String.format("%.2f KiB", bytes / ki); } if (bytes < gi) { return String.format("%.2f MiB", bytes / mi); } if (bytes < ti) { return String.format("%.2f GiB", bytes / gi); } return String.format("%.2f TiB", bytes / ti); } /** * Test if a String starts with one of the prefix of a list in an array * @param s String to test * @param prefixes list of prefixes * @return true if the String starts with one of the prefix of a list in an * array */ public static final boolean startsWith(final String s, final String[] prefixes) { if (s == null || prefixes == null) { return false; } for (String p : prefixes) { if (s.startsWith(p)) { return true; } } return false; } /** * Get the content type of a file for common file extensions * @param extension extension to use * @return the content type of an empty string if the content type was not * found */ public static final String getCommonContentTypeFromExtension( final String extension) { if (extension == null) { return null; } switch (extension.toLowerCase()) { case ".htm": case ".html": return "text/html"; case ".xml": return "text/xml"; case ".txt": case ".pl": case ".pm": case ".py": case ".r": case ".rb": case ".java": return "text/plain"; case ".jpeg": case ".jpg": case ".jpe": return "image/jpeg"; case ".tif": case ".tiff": return "image/tiff"; case ".png": return "image/png"; case ".pdf": return "application/pdf"; default: return ""; } } /** * Replace the prefix of a string. * @param s the string to process * @param oldPrefix prefix to replace * @param newPrefix new prefix * @return the string with the new prefix */ public static String replacePrefix(final String s, final String oldPrefix, final String newPrefix) { if (s == null) { return null; } if (oldPrefix == null || newPrefix == null) { return s; } if (!s.startsWith(oldPrefix)) { return s; } final int prefixLen = oldPrefix.length(); return newPrefix + s.substring(prefixLen); } /** * Serialize a collection of strings in a string. * @param strings strings to serialize * @return a String with all strings serialized */ public static String serializeStringArray(final Collection<String> strings) { if (strings == null) { return null; } final StringBuilder sb = new StringBuilder(); sb.append('['); boolean first = true; for (String s : strings) { if (first) { first = false; } else { sb.append(','); } if (s != null) { sb.append(s.replace("\\", "\\\\").replace(",", "\\,")); } } sb.append(']'); return sb.toString(); } /** * Deserialize a string to a list of strings. * @param serializedString string to deserialize * @return a list of string */ public static List<String> deserializeStringArray( final String serializedString) { if (serializedString == null) { return null; } String s = serializedString.trim(); if (s.charAt(0) != '[' || s.charAt(s.length() - 1) != ']') { return Collections.singletonList(serializedString); } s = s.substring(1, s.length() - 1); final List<String> result = new ArrayList<>(); int last = 0; boolean escapeNext = false; for (int i = 0; i < s.length(); i++) { if (escapeNext) { escapeNext = false; continue; } if (s.charAt(i) == '\\') { escapeNext = true; continue; } if (s.charAt(i) == ',') { result.add( s.substring(last, i).replace("\\\\", "\\").replace("\\,", ",")); last = i + 1; } } result.add(s.substring(last).replace("\\\\", "\\").replace("\\,", ",")); return result; } /** * Convert 0-15 integer number to a letter * @param i the integer to convert * @return a letter as a char */ public static char toLetter(final int i) { if (i < 0) { return '-'; } if (i > 25) { return '-'; } return (char) (i + 97); } /** * Trim a string * @param s the string to trim * @return null if the parameter is null or a trimmed string */ public static String trim(final String s) { return s == null ? null : s.trim(); } /** * Join elements of an array of strings into a string. * @param array array of strings to join * @param separator separator to use */ public static String join(final String[] array, final String separator) { if (array == null) { return null; } final StringBuilder sb = new StringBuilder(); for (int i = 0; i < array.length; i++) { if (i > 0 && separator != null) { sb.append(separator); } sb.append(array[i]); } return sb.toString(); } /** * Join elements of an array of objects into a string. * @param array array of objects to join * @param separator separator to use */ public static String join(final Object[] array, final String separator) { if (array == null) { return null; } final StringBuilder sb = new StringBuilder(); for (int i = 0; i < array.length; i++) { if (i > 0 && separator != null) { sb.append(separator); } sb.append(array[i]); } return sb.toString(); } /** * Split a string in substring of same length * @param s String to split * @param length length of the output strings * @return a Iterable object */ public static Iterable<String> splitStringIterator(final String s, final int length) { if (s == null || length < 1) { return null; } return new IterableString() { int pos = 0; final int len = s.length(); @Override public boolean hasNext() { return this.pos < this.len; } @Override public String next() { final int endPos = (this.pos + length) > this.len ? this.len : this.pos + length; final String result = s.substring(this.pos, endPos); this.pos += length; return result; } @Override public void remove() { } @Override public Iterator<String> iterator() { return this; } }; } private interface IterableString extends Iterable<String>, Iterator<String> { } /** * Test if a string is null or empty * @param s string to test * @return true if the input string is null or empty */ public static boolean isNullOrEmpty(final String s) { return s == null || s.isEmpty(); } /** * Split a shell command line. * @param commandline the command to parse * @return a list with the command line arguments */ public static List<String> splitShellCommandLine(final String commandline) { if (commandline == null) { return null; } final String s = commandline.trim(); final List<String> result = new ArrayList<>(); final StringBuilder sb = new StringBuilder(); boolean escape = false; boolean inArgument = false; char quote = ' '; for (int i = 0; i < s.length(); i++) { final char c = s.charAt(i); if (escape) { if (c == '\"') { sb.append(c); } escape = false; continue; } if (c == '\\') { escape = true; continue; } if ((c == '"' || c == '\'') && !inArgument) { quote = c; inArgument = true; continue; } if ((c == ' ' && !inArgument) || (c == quote && inArgument)) { if (inArgument) { result.add(sb.toString()); } else { String s2 = sb.toString().trim(); if (!s2.isEmpty()) { result.add(s2); } } sb.setLength(0); inArgument = false; continue; } sb.append(c); } if (inArgument) { result.add(sb.toString()); } else { String s2 = sb.toString().trim(); if (!s2.isEmpty()) { result.add(s2); } } return Collections.unmodifiableList(result); } /** * Returns a string with double quotes at the beginning and at the end of the * string. * @param s the string * @return a string with double quotes at the beginning and at the end of the * string or null if s is null */ public static String doubleQuotes(final String s) { if (s == null) { return null; } return '"' + s + '"'; } /** * Remove double quotes at the beginning and at the end of the string. * @param s the string. * @return a string without double quote at the beginning and at the end of * the string or null if s is null */ public static String unDoubleQuotes(final String s) { if (s == null) { return null; } final int len = s.length(); if (len < 2) { return s; } if (s.charAt(0) == '"' && s.charAt(len - 1) == '"') { return s.substring(1, len - 1); } return s; } /** * Convert a stack trace of an exception into a string. * @param t the throwable exception * @return a string with the stack strace */ public static String stackTraceToString(final Throwable t) { if (t == null) { return null; } final StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); return sw.toString(); } /** * Escape XML string. * @param s the string to escape * @return an escaped string */ public static String xmlEscape(final String s) { if (s == null) { return null; } final StringBuilder sb = new StringBuilder(); final int len = s.length(); for (int i = 0; i < len; i++) { final char c = s.charAt(i); switch (c) { case '"': sb.append("""); break; case '\'': sb.append("'"); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '&': sb.append("&"); break; default: sb.append(c); } } return sb.toString(); } // // Constructor // private StringUtils() { } }