/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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 com.google.dart.server.utilities.general; import com.google.common.collect.Interner; import com.google.common.collect.Interners; import com.google.common.collect.Lists; import java.util.List; /** * The class {@code StringUtilities} defines utility methods for strings. * * @coverage dart.server.utilities */ public final class StringUtilities { /** * The empty String {@code ""}. */ public static final String EMPTY = ""; /** * An empty array of {@link String}s. */ public static final String[] EMPTY_ARRAY = new String[0]; /** * An empty list of {@link String}s. */ public static final List<String> EMPTY_LIST = Lists.newArrayList(); /** * The {@link Interner} instance to use for {@link #intern(String)}. */ private static final Interner<String> INTERNER = Interners.newWeakInterner(); /** * Abbreviates a String using ellipses inserted at left. */ public static String abbreviateLeft(String s, int width) { int length = s.length(); if (length > width) { if (width < 4) { throw new IllegalArgumentException("Minimal width is 4"); } return "..." + s.substring(length - (width - 3)); } return s; } /** * Return {@code true} if the three-character substring occurs at the end of the given string. * * @param string the string being searched * @param char1 the first character in the substring * @param char2 the second character in the substring * @param char3 the third character in the substring * @return {@code true} if the substring occurs at the end of the string */ public static boolean endsWith3(String string, int char1, int char2, int char3) { int length = string.length(); return length >= 3 && string.charAt(length - 3) == char1 && string.charAt(length - 2) == char2 && string.charAt(length - 1) == char3; } /** * Return {@code true} if the given string ends with the given character. * * @param string the string being searched * @param character the character being tested for * @return {@code true} if the string ends with the character */ public static boolean endsWithChar(String string, int character) { int length = string.length(); return length > 0 && string.charAt(length - 1) == character; } /** * Return the index of the first occurrence of the given character in the given string that is at * or after the given starting index. Return {@code -1} if the substring does not occur. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @return the index of the first occurrence of the substring */ public static int indexOf1(String string, int startIndex, int char1) { int index = startIndex; int last = string.length(); while (index < last) { if (string.charAt(index) == char1) { return index; } index++; } return -1; } /** * Return the index of the first occurrence of the given characters as a substring of the given * string that is at or after the given starting index. Return {@code -1} if the substring does * not occur. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @return the index of the first occurrence of the substring */ public static int indexOf2(String string, int startIndex, int char1, int char2) { int index = startIndex; int last = string.length() - 1; while (index < last) { if (string.charAt(index) == char1 && string.charAt(index + 1) == char2) { return index; } index++; } return -1; } /** * Return the index of the first occurrence of the given characters as a substring of the given * string that is at or after the given starting index. Return {@code -1} if the substring does * not occur. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @param char3 the third character in the substring * @param char4 the fourth character in the substring * @return the index of the first occurrence of the substring */ public static int indexOf4(String string, int startIndex, int char1, int char2, int char3, int char4) { int index = startIndex; int last = string.length() - 3; while (index < last) { if (string.charAt(index) == char1 && string.charAt(index + 1) == char2 && string.charAt(index + 2) == char3 && string.charAt(index + 3) == char4) { return index; } index++; } return -1; } /** * Return the index of the first occurrence of the given characters as a substring of the given * string that is at or after the given starting index. Return {@code -1} if the substring does * not occur. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @param char3 the third character in the substring * @param char4 the fourth character in the substring * @param char5 the fifth character in the substring * @return the index of the first occurrence of the substring */ public static int indexOf5(String string, int startIndex, int char1, int char2, int char3, int char4, int char5) { int index = startIndex; int last = string.length() - 4; while (index < last) { if (string.charAt(index) == char1 && string.charAt(index + 1) == char2 && string.charAt(index + 2) == char3 && string.charAt(index + 3) == char4 && string.charAt(index + 4) == char5) { return index; } index++; } return -1; } /** * Return the index of the first not letter/digit character in the given string that is at or * after the given starting index. Return the length of the given string if the all characters to * the end are letters/digits. * * @param string the string being searched * @param startIndex the index at which the search should begin * @return the index of the first not letter/digit character */ public static int indexOfFirstNotLetterDigit(String string, int startIndex) { int index = startIndex; int last = string.length(); while (index < last) { char c = string.charAt(index); if (!Character.isLetterOrDigit(c)) { return index; } index++; } return last; } /** * Returns a canonical representation for the given {@link String}. * * @return the given {@link String} or its canonical representation. */ public static String intern(String str) { if (str == null) { return null; } str = new String(str); return INTERNER.intern(str); } /** * <p> * Checks if the CharSequence contains only Unicode letters. * </p> * <p> * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return * {@code false}. * </p> * * <pre> * StringUtils.isAlpha(null) = false * StringUtils.isAlpha("") = false * StringUtils.isAlpha(" ") = false * StringUtils.isAlpha("abc") = true * StringUtils.isAlpha("ab2c") = false * StringUtils.isAlpha("ab-c") = false * </pre> * * @param cs the CharSequence to check, may be null * @return {@code true} if only contains letters, and is non-null */ public static boolean isAlpha(CharSequence cs) { if (cs == null || cs.length() == 0) { return false; } int sz = cs.length(); for (int i = 0; i < sz; i++) { if (Character.isLetter(cs.charAt(i)) == false) { return false; } } return true; } /** * Return {@code true} if the given CharSequence is empty ("") or null. * * <pre> * StringUtils.isEmpty(null) = true * StringUtils.isEmpty("") = true * StringUtils.isEmpty(" ") = false * StringUtils.isEmpty("bob") = false * StringUtils.isEmpty(" bob ") = false * </pre> * * @param cs the CharSequence to check, may be null * @return {@code true} if the CharSequence is empty or null */ public static boolean isEmpty(CharSequence cs) { return cs == null || cs.length() == 0; } /** * <p> * Checks if the String can be used as a tag name. * </p> * <p> * {@code null} will return {@code false}. An empty String (length()=0) will return {@code false}. * </p> * * <pre> * StringUtils.isAlpha(null) = false * StringUtils.isAlpha("") = false * StringUtils.isAlpha(" ") = false * StringUtils.isAlpha("ab c") = false * StringUtils.isAlpha("abc") = true * StringUtils.isAlpha("ab2c") = true * StringUtils.isAlpha("ab-c") = true * </pre> * * @param s the String to check, may be null * @return {@code true} if can be used as a tag name, and is non-null */ public static boolean isTagName(String s) { if (s == null || s.length() == 0) { return false; } int sz = s.length(); for (int i = 0; i < sz; i++) { char c = s.charAt(i); if (!Character.isLetter(c)) { if (i == 0) { return false; } if (!Character.isDigit(c) && c != '-') { return false; } } } return true; } /** * Produce a string containing all of the names in the given array, surrounded by single quotes, * and separated by commas. The list must contain at least two elements. * * @param names the names to be printed * @return the result of printing the names */ public static String printListOfQuotedNames(String[] names) { if (names == null) { throw new IllegalArgumentException("The list must not be null"); } int count = names.length; if (count < 2) { throw new IllegalArgumentException("The list must contain at least two names"); } StringBuilder builder = new StringBuilder(); builder.append("'"); builder.append(names[0]); builder.append("'"); for (int i = 1; i < count - 1; i++) { builder.append(", '"); builder.append(names[i]); builder.append("'"); } builder.append(" and '"); builder.append(names[count - 1]); builder.append("'"); return builder.toString(); } /** * Return {@code true} if the two-character substring occurs at the given index in the given * string. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @return {@code true} if the substring occurs at the given index in the string */ public static boolean startsWith2(String string, int startIndex, int char1, int char2) { return string.length() - startIndex >= 2 && string.charAt(startIndex) == char1 && string.charAt(startIndex + 1) == char2; } /** * Return {@code true} if the three-character substring occurs at the given index in the given * string. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @param char3 the third character in the substring * @return {@code true} if the substring occurs at the given index in the string */ public static boolean startsWith3(String string, int startIndex, int char1, int char2, int char3) { return string.length() - startIndex >= 3 && string.charAt(startIndex) == char1 && string.charAt(startIndex + 1) == char2 && string.charAt(startIndex + 2) == char3; } /** * Return {@code true} if the four-character substring occurs at the given index in the given * string. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @param char3 the third character in the substring * @param char4 the fourth character in the substring * @return {@code true} if the substring occurs at the given index in the string */ public static boolean startsWith4(String string, int startIndex, int char1, int char2, int char3, int char4) { return string.length() - startIndex >= 4 && string.charAt(startIndex) == char1 && string.charAt(startIndex + 1) == char2 && string.charAt(startIndex + 2) == char3 && string.charAt(startIndex + 3) == char4; } /** * Return {@code true} if the five-character substring occurs at the given index in the given * string. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @param char3 the third character in the substring * @param char4 the fourth character in the substring * @param char5 the fifth character in the substring * @return {@code true} if the substring occurs at the given index in the string */ public static boolean startsWith5(String string, int startIndex, int char1, int char2, int char3, int char4, int char5) { return string.length() - startIndex >= 5 && string.charAt(startIndex) == char1 && string.charAt(startIndex + 1) == char2 && string.charAt(startIndex + 2) == char3 && string.charAt(startIndex + 3) == char4 && string.charAt(startIndex + 4) == char5; } /** * Return {@code true} if the six-character substring occurs at the given index in the given * string. * * @param string the string being searched * @param startIndex the index at which the search should begin * @param char1 the first character in the substring * @param char2 the second character in the substring * @param char3 the third character in the substring * @param char4 the fourth character in the substring * @param char5 the fifth character in the substring * @param char6 the sixth character in the substring * @return {@code true} if the substring occurs at the given index in the string */ public static boolean startsWith6(String string, int startIndex, int char1, int char2, int char3, int char4, int char5, int char6) { return string.length() - startIndex >= 6 && string.charAt(startIndex) == char1 && string.charAt(startIndex + 1) == char2 && string.charAt(startIndex + 2) == char3 && string.charAt(startIndex + 3) == char4 && string.charAt(startIndex + 4) == char5 && string.charAt(startIndex + 5) == char6; } /** * Return {@code true} if the given string starts with the given character. * * @param string the string being searched * @param character the character being tested for * @return {@code true} if the string starts with the character */ public static boolean startsWithChar(String string, int character) { return string.length() > 0 && string.charAt(0) == character; } /** * <p> * Gets the substring after the first occurrence of a separator. The separator is not returned. * </p> * <p> * A {@code null} string input will return {@code null}. An empty ("") string input will return * the empty string. A {@code null} separator will return the empty string if the input string is * not {@code null}. * </p> * <p> * If nothing is found, the empty string is returned. * </p> * * <pre> * StringUtils.substringAfter(null, *) = null * StringUtils.substringAfter("", *) = "" * StringUtils.substringAfter(*, null) = "" * StringUtils.substringAfter("abc", "a") = "bc" * StringUtils.substringAfter("abcba", "b") = "cba" * StringUtils.substringAfter("abc", "c") = "" * StringUtils.substringAfter("abc", "d") = "" * StringUtils.substringAfter("abc", "") = "abc" * </pre> * * @param str the String to get a substring from, may be null * @param separator the String to search for, may be null * @return the substring after the first occurrence of the separator, {@code null} if null String * input */ public static String substringAfter(String str, String separator) { if (isEmpty(str)) { return str; } if (separator == null) { return EMPTY; } int pos = str.indexOf(separator); if (pos == -1) { return EMPTY; } return str.substring(pos + separator.length()); } /** * Return the substring before the first occurrence of a separator. The separator is not returned. * <p> * A {@code null} string input will return {@code null}. An empty ("") string input will return * the empty string. A {@code null} separator will return the input string. * <p> * If nothing is found, the string input is returned. * * <pre> * StringUtils.substringBefore(null, *) = null * StringUtils.substringBefore("", *) = "" * StringUtils.substringBefore("abc", "a") = "" * StringUtils.substringBefore("abcba", "b") = "a" * StringUtils.substringBefore("abc", "c") = "ab" * StringUtils.substringBefore("abc", "d") = "abc" * StringUtils.substringBefore("abc", "") = "" * StringUtils.substringBefore("abc", null) = "abc" * </pre> * * @param str the string to get a substring from, may be null * @param separator the string to search for, may be null * @return the substring before the first occurrence of the separator */ public static String substringBefore(String str, String separator) { if (isEmpty(str) || separator == null) { return str; } if (separator.length() == 0) { return EMPTY; } int pos = str.indexOf(separator); if (pos == -1) { return str; } return str.substring(0, pos); } /** * Return the substring before the first occurrence of a separator. The separator is not included * in the returned value. * <p> * A {@code null} string input will return {@code null}. An empty ("") string input will return * the empty string. * <p> * If nothing is found, the string input is returned. * * <pre> * StringUtils.substringBefore(null, *) = null * StringUtils.substringBefore("", *) = "" * StringUtils.substringBefore("abc", 'a') = "" * StringUtils.substringBefore("abcba", 'b') = "a" * StringUtils.substringBefore("abc", 'c') = "ab" * StringUtils.substringBefore("abc", 'd') = "abc" * </pre> * * @param str the string to get a substring from, may be null * @param separator the character to search for * @return the substring before the first occurrence of the separator */ public static String substringBeforeChar(String str, int separator) { if (isEmpty(str)) { return str; } int pos = str.indexOf(separator); if (pos < 0) { return str; } return str.substring(0, pos); } /** * Prevent the creation of instances of this class. */ private StringUtilities() { } }