2012-03-08 08:07:02 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* 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 com.android.inputmethod.latin;
|
|
|
|
|
|
|
|
import android.text.TextUtils;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
2012-04-04 05:30:42 +00:00
|
|
|
import java.util.Locale;
|
2012-03-08 08:07:02 +00:00
|
|
|
|
2012-08-29 08:26:00 +00:00
|
|
|
public final class StringUtils {
|
2013-04-04 12:14:37 +00:00
|
|
|
public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case
|
|
|
|
public static final int CAPITALIZE_FIRST = 1; // First only
|
|
|
|
public static final int CAPITALIZE_ALL = 2; // All caps
|
|
|
|
|
2012-03-08 08:07:02 +00:00
|
|
|
private StringUtils() {
|
|
|
|
// This utility class is not publicly instantiable.
|
|
|
|
}
|
|
|
|
|
2012-10-03 06:19:43 +00:00
|
|
|
public static int codePointCount(final String text) {
|
2012-03-08 08:07:02 +00:00
|
|
|
if (TextUtils.isEmpty(text)) return 0;
|
|
|
|
return text.codePointCount(0, text.length());
|
|
|
|
}
|
|
|
|
|
2012-10-03 06:19:43 +00:00
|
|
|
public static boolean containsInArray(final String key, final String[] array) {
|
2012-04-19 07:39:25 +00:00
|
|
|
for (final String element : array) {
|
|
|
|
if (key.equals(element)) return true;
|
2012-03-08 08:07:02 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-10-03 06:19:43 +00:00
|
|
|
public static boolean containsInCsv(final String key, final String csv) {
|
2012-04-19 07:39:25 +00:00
|
|
|
if (TextUtils.isEmpty(csv)) return false;
|
|
|
|
return containsInArray(key, csv.split(","));
|
|
|
|
}
|
|
|
|
|
2012-10-03 06:19:43 +00:00
|
|
|
public static String appendToCsvIfNotExists(final String key, final String csv) {
|
2012-04-19 07:39:25 +00:00
|
|
|
if (TextUtils.isEmpty(csv)) return key;
|
|
|
|
if (containsInCsv(key, csv)) return csv;
|
|
|
|
return csv + "," + key;
|
|
|
|
}
|
|
|
|
|
2012-10-03 06:19:43 +00:00
|
|
|
public static String removeFromCsvIfExists(final String key, final String csv) {
|
2012-04-19 07:39:25 +00:00
|
|
|
if (TextUtils.isEmpty(csv)) return "";
|
|
|
|
final String[] elements = csv.split(",");
|
|
|
|
if (!containsInArray(key, elements)) return csv;
|
2012-08-21 07:34:55 +00:00
|
|
|
final ArrayList<String> result = CollectionUtils.newArrayList(elements.length - 1);
|
2012-04-19 07:39:25 +00:00
|
|
|
for (final String element : elements) {
|
|
|
|
if (!key.equals(element)) result.add(element);
|
|
|
|
}
|
|
|
|
return TextUtils.join(",", result);
|
2012-03-08 08:07:02 +00:00
|
|
|
}
|
|
|
|
|
2012-12-27 05:48:47 +00:00
|
|
|
/**
|
|
|
|
* Find a string that start with specified prefix from an array.
|
|
|
|
*
|
|
|
|
* @param prefix a prefix string to find.
|
|
|
|
* @param array an string array to be searched.
|
|
|
|
* @return the rest part of the string that starts with the prefix.
|
|
|
|
* Returns null if it couldn't be found.
|
|
|
|
*/
|
|
|
|
public static String findPrefixedString(final String prefix, final String[] array) {
|
|
|
|
for (final String element : array) {
|
|
|
|
if (element.startsWith(prefix)) {
|
|
|
|
return element.substring(prefix.length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2012-03-08 08:07:02 +00:00
|
|
|
/**
|
|
|
|
* Remove duplicates from an array of strings.
|
|
|
|
*
|
2012-04-06 02:49:48 +00:00
|
|
|
* This method will always keep the first occurrence of all strings at their position
|
2012-03-08 08:07:02 +00:00
|
|
|
* in the array, removing the subsequent ones.
|
|
|
|
*/
|
2012-10-03 06:19:43 +00:00
|
|
|
public static void removeDupes(final ArrayList<String> suggestions) {
|
2012-03-08 08:07:02 +00:00
|
|
|
if (suggestions.size() < 2) return;
|
|
|
|
int i = 1;
|
|
|
|
// Don't cache suggestions.size(), since we may be removing items
|
|
|
|
while (i < suggestions.size()) {
|
2012-10-03 06:19:43 +00:00
|
|
|
final String cur = suggestions.get(i);
|
2012-03-08 08:07:02 +00:00
|
|
|
// Compare each suggestion with each previous suggestion
|
|
|
|
for (int j = 0; j < i; j++) {
|
2012-10-03 06:19:43 +00:00
|
|
|
final String previous = suggestions.get(j);
|
2012-03-08 08:07:02 +00:00
|
|
|
if (TextUtils.equals(cur, previous)) {
|
2012-03-13 07:52:42 +00:00
|
|
|
suggestions.remove(i);
|
2012-03-08 08:07:02 +00:00
|
|
|
i--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
2012-04-04 05:30:42 +00:00
|
|
|
|
2012-10-03 06:19:43 +00:00
|
|
|
public static String toTitleCase(final String s, final Locale locale) {
|
2012-04-04 05:30:42 +00:00
|
|
|
if (s.length() <= 1) {
|
|
|
|
// TODO: is this really correct? Shouldn't this be s.toUpperCase()?
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
// TODO: fix the bugs below
|
|
|
|
// - This does not work for Greek, because it returns upper case instead of title case.
|
|
|
|
// - It does not work for Serbian, because it fails to account for the "lj" character,
|
|
|
|
// which should be "Lj" in title case and "LJ" in upper case.
|
|
|
|
// - It does not work for Dutch, because it fails to account for the "ij" digraph, which
|
|
|
|
// are two different characters but both should be capitalized as "IJ" as if they were
|
|
|
|
// a single letter.
|
|
|
|
// - It also does not work with unicode surrogate code points.
|
|
|
|
return s.toUpperCase(locale).charAt(0) + s.substring(1);
|
|
|
|
}
|
2012-04-17 06:55:17 +00:00
|
|
|
|
2012-10-03 06:19:43 +00:00
|
|
|
private static final int[] EMPTY_CODEPOINTS = {};
|
|
|
|
|
2012-04-17 06:55:17 +00:00
|
|
|
public static int[] toCodePointArray(final String string) {
|
2012-10-03 06:19:43 +00:00
|
|
|
final int length = string.length();
|
2012-06-25 18:17:48 +00:00
|
|
|
if (length <= 0) {
|
2012-10-03 06:19:43 +00:00
|
|
|
return EMPTY_CODEPOINTS;
|
2012-06-25 18:17:48 +00:00
|
|
|
}
|
2012-10-03 06:19:43 +00:00
|
|
|
final int[] codePoints = new int[string.codePointCount(0, length)];
|
|
|
|
int destIndex = 0;
|
|
|
|
for (int index = 0; index < length; index = string.offsetByCodePoints(index, 1)) {
|
|
|
|
codePoints[destIndex] = string.codePointAt(index);
|
|
|
|
destIndex++;
|
2012-04-17 06:55:17 +00:00
|
|
|
}
|
|
|
|
return codePoints;
|
|
|
|
}
|
2012-09-10 10:27:45 +00:00
|
|
|
|
2013-02-12 07:00:28 +00:00
|
|
|
public static String[] parseCsvString(final String text) {
|
|
|
|
final int size = text.length();
|
|
|
|
if (size == 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (codePointCount(text) == 1) {
|
|
|
|
return text.codePointAt(0) == Constants.CSV_SEPARATOR ? null : new String[] { text };
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayList<String> list = null;
|
|
|
|
int start = 0;
|
|
|
|
for (int pos = 0; pos < size; pos++) {
|
|
|
|
final char c = text.charAt(pos);
|
|
|
|
if (c == Constants.CSV_SEPARATOR) {
|
|
|
|
// Skip empty entry.
|
|
|
|
if (pos - start > 0) {
|
|
|
|
if (list == null) {
|
|
|
|
list = CollectionUtils.newArrayList();
|
|
|
|
}
|
|
|
|
list.add(text.substring(start, pos));
|
|
|
|
}
|
|
|
|
// Skip comma
|
|
|
|
start = pos + 1;
|
|
|
|
} else if (c == Constants.CSV_ESCAPE) {
|
|
|
|
// Skip escape character and escaped character.
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
final String remain = (size - start > 0) ? text.substring(start) : null;
|
|
|
|
if (list == null) {
|
|
|
|
return remain != null ? new String[] { remain } : null;
|
|
|
|
}
|
|
|
|
if (remain != null) {
|
|
|
|
list.add(remain);
|
|
|
|
}
|
|
|
|
return list.toArray(new String[list.size()]);
|
|
|
|
}
|
2013-04-04 12:14:37 +00:00
|
|
|
|
|
|
|
// This method assumes the text is not empty or null.
|
|
|
|
public static int getCapitalizationType(final String text) {
|
|
|
|
// If the first char is not uppercase, then the word is either all lower case or
|
|
|
|
// camel case, and in either case we return CAPITALIZE_NONE.
|
|
|
|
if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE;
|
|
|
|
final int len = text.length();
|
|
|
|
int capsCount = 1;
|
|
|
|
int letterCount = 1;
|
|
|
|
for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) {
|
|
|
|
if (1 != capsCount && letterCount != capsCount) break;
|
|
|
|
final int codePoint = text.codePointAt(i);
|
|
|
|
if (Character.isUpperCase(codePoint)) {
|
|
|
|
++capsCount;
|
|
|
|
++letterCount;
|
|
|
|
} else if (Character.isLetter(codePoint)) {
|
|
|
|
// We need to discount non-letters since they may not be upper-case, but may
|
|
|
|
// still be part of a word (e.g. single quote or dash, as in "IT'S" or "FULL-TIME")
|
|
|
|
++letterCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We know the first char is upper case. So we want to test if either every letter other
|
|
|
|
// than the first is lower case, or if they are all upper case. If the string is exactly
|
|
|
|
// one char long, then we will arrive here with letterCount 1, and this is correct, too.
|
|
|
|
if (1 == capsCount) return CAPITALIZE_FIRST;
|
|
|
|
return (letterCount == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE);
|
|
|
|
}
|
2012-03-08 08:07:02 +00:00
|
|
|
}
|