/******************************************************************************* * Copyright (c) 2011-2015 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.openshift.common.core.utils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.lang.WordUtils; /** * @author André Dietisheim */ public class StringUtils { private static final String LINE_SEPARATOR_KEY = "line.separator"; private static final String SHORTENING_MARKER = "..."; public static String pluralize(String value) { return value + "s"; } public static String null2emptyString(String value) { if (value != null) { return value; } return ""; } public static String toStringOrNull(Object value) { if (value == null) { return null; } return String.valueOf(value); } /** * Returns true if value is null or empty string. * @param value * @return */ public static boolean isEmpty(String value) { return value == null || value.length() == 0; } public static boolean isEmpty(Object value) { return (value instanceof String) && isEmpty((String) value); } public static <T> String toString(List<T> elements) { return toString(elements, new ToStringConverter<T>() { @Override public String toString(T object) { if (object == null) { return null; } return String.valueOf(object); } }); } public static <T> String toString(Collection<T> elements, ToStringConverter<T> converter) { if (elements == null || elements.isEmpty()) { return ""; } StringBuilder builder = new StringBuilder(); int i = 0; for(T element : elements) { builder.append(converter.toString(element)); if (++i < elements.size()) { builder.append(", "); } } return builder.toString(); } public static <T> String toString(Map<String, String> map) { if (map == null || map.isEmpty()) { return null; } return toString(map.entrySet(), new ToStringConverter<Entry<String, String>>() { @Override public String toString(Entry<String, String> entry) { return new StringBuilder(entry.getKey()) .append('=') .append(entry.getValue()) .toString(); } }); } public static interface ToStringConverter<T> { public String toString(T object); } public static String getLineSeparator() { return System.getProperty(LINE_SEPARATOR_KEY); } public static boolean isAlphaNumeric(String value) { for (int i = 0; i < value.length(); ++i) { final char c = value.charAt(i); if (!Character.isLetterOrDigit(c)) { return false; } } return true; } public static boolean isAlphaNumericOrUnderscore(String value) { for (int i = 0; i < value.length(); ++i) { final char c = value.charAt(i); if (c != '_') { if (!Character.isLetterOrDigit(c)) { return false; } } } return true; } public static boolean startsWithLetterOrUnderscore(String value) { if (isEmpty(value)) { return false; } char character = value.charAt(0); return character == '_' || Character.isLetter(character); } public static boolean isEmptyOrNull(String value) { return value == null || value.isEmpty(); } public static String shorten(String text, int maxLength) { if (text.length() < maxLength) { return text; } int availableCharacters = maxLength - SHORTENING_MARKER.length(); if(availableCharacters <= 0) { //Did we ask for it? Yeah, we got it. return SHORTENING_MARKER; } //This is how computer enhances math: //availableCharacters = (availableCharacters + 1) / 2 + availableCharacters / 2 return new StringBuilder(text.substring(0, (availableCharacters + 1) / 2)) .append(SHORTENING_MARKER) .append(text.substring(text.length() - availableCharacters / 2, text.length())) .toString(); } /** * * @param parts * @param maxLength * @return Passed array parts with modified elements. */ public static String[] shorten(String[] parts, int maxLength) { if(parts == null || parts.length == 0) { return parts; } else if(parts.length == 1) { parts[0] = shorten(parts[0], maxLength); } else if(parts.length == 2) { //Let's take most useful case 2 separately. int length0 = isEmpty(parts[0]) ? 0 : parts[0].length(); int length1 = isEmpty(parts[1]) ? 0 : parts[1].length(); if(length0 + length1 > maxLength) { int partLimit = maxLength / 2; if(length1 <= partLimit) { parts[0] = shorten(parts[0], maxLength - length1); } else if(length0 <= partLimit) { parts[1] = shorten(parts[1], maxLength - length0); } else { parts[0] = shorten(parts[0], partLimit); parts[1] = shorten(parts[1], partLimit); } } } else { //Let's be cool mathematicians here. int[] lengths = new int[parts.length]; int totalLength = 0; for (int i = 0; i < parts.length; i++) { lengths[i] = isEmpty(parts[i]) ? 0 : parts[i].length(); totalLength += lengths[i]; } if(totalLength > maxLength) { int totalCut = totalLength - maxLength; //Let's distribute that cut proportionally. int[] cuts = new int[parts.length]; int currentCut = 0; for (int i = 0; i < parts.length; i++) { if(lengths[i] >= SHORTENING_MARKER.length()) { //Cannot cut more than adding ellipses is going to cut. cuts[i] = (lengths[i] * totalCut) / totalLength; currentCut += cuts[i]; } } //Distribute a few last chars to cut, carefully, one by one. while (currentCut < totalCut) { boolean changed = false; for (int i = 0; i < parts.length; i++) { if(lengths[i] - cuts[i] > SHORTENING_MARKER.length()) { //Still remembering that ellipses replace that much. cuts[i]++; currentCut++; if(currentCut == totalCut) { break; } changed = true; } } if(!changed) { //At this moment, it is possible that currentCut < totalCut, //but there is nothing to take anymore, I swear. break; } } //Measured seven times, now cut them once. for (int i = 0; i < parts.length; i++) { if(cuts[i] > 0) { parts[i] = shorten(parts[i], parts[i].length() - cuts[i]); } } } } return parts; } public static String getWithoutSuffix(String string, String suffix) { String stringNoSuffix = string; int suffixIndex = string.indexOf(suffix); if (suffixIndex >= 0) { stringNoSuffix = string.substring(0, suffixIndex); } return stringNoSuffix; } public static String trim(String string) { if (string == null) { return string; } return string.trim(); } public static String toLowerCase(String string) { if (isEmpty(string)) { return string; } return string.toLowerCase(); } public static boolean areEqual(String thisString, String thatString) { if (thisString == null) { return thatString == null; } else { return thisString.equals(thatString); } } /** * Rudimentary implementation of humanizing a String * to a human readable form (e.g. Build Configs from buildConfigs) * @param string * @return */ public static String humanize(String value) { String[] parts = org.apache.commons.lang.StringUtils.splitByCharacterTypeCamelCase(value); String split = org.apache.commons.lang.StringUtils.join(parts, " "); return WordUtils.capitalize(split); } /** * Serialize Map<String, String> to a string * of key value pairs * @param map * @return String */ public static String serialize(Map<String, String> map){ List<String> out = new ArrayList<>(map.size()); for (Map.Entry<String, String> entry : map.entrySet()) { out.add(String.format("%s=%s", entry.getKey(), entry.getValue())); } Collections.sort(out); return org.apache.commons.lang.StringUtils.join(out.toArray(), ","); } /** * Remove all trailing <code>/</code> from a {@link String}. * @param value * @return the value without trailing <code>/</code> */ public static String removeTrailingSlashes(String value) { return removeAll("/*$", value); } public static String removeAll(String regex, String value) { if (isEmpty(value) || isEmpty(regex)) { return value; } return value.replaceAll(regex, ""); } }