Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.inputmethod.latin;
     18 
     19 import android.text.TextUtils;
     20 
     21 import java.util.ArrayList;
     22 import java.util.Locale;
     23 
     24 public class StringUtils {
     25     private StringUtils() {
     26         // This utility class is not publicly instantiable.
     27     }
     28 
     29     public static int codePointCount(String text) {
     30         if (TextUtils.isEmpty(text)) return 0;
     31         return text.codePointCount(0, text.length());
     32     }
     33 
     34     public static boolean containsInArray(String key, String[] array) {
     35         for (final String element : array) {
     36             if (key.equals(element)) return true;
     37         }
     38         return false;
     39     }
     40 
     41     public static boolean containsInCsv(String key, String csv) {
     42         if (TextUtils.isEmpty(csv)) return false;
     43         return containsInArray(key, csv.split(","));
     44     }
     45 
     46     public static String appendToCsvIfNotExists(String key, String csv) {
     47         if (TextUtils.isEmpty(csv)) return key;
     48         if (containsInCsv(key, csv)) return csv;
     49         return csv + "," + key;
     50     }
     51 
     52     public static String removeFromCsvIfExists(String key, String csv) {
     53         if (TextUtils.isEmpty(csv)) return "";
     54         final String[] elements = csv.split(",");
     55         if (!containsInArray(key, elements)) return csv;
     56         final ArrayList<String> result = new ArrayList<String>(elements.length - 1);
     57         for (final String element : elements) {
     58             if (!key.equals(element)) result.add(element);
     59         }
     60         return TextUtils.join(",", result);
     61     }
     62 
     63     /**
     64      * Returns true if a and b are equal ignoring the case of the character.
     65      * @param a first character to check
     66      * @param b second character to check
     67      * @return {@code true} if a and b are equal, {@code false} otherwise.
     68      */
     69     public static boolean equalsIgnoreCase(char a, char b) {
     70         // Some language, such as Turkish, need testing both cases.
     71         return a == b
     72                 || Character.toLowerCase(a) == Character.toLowerCase(b)
     73                 || Character.toUpperCase(a) == Character.toUpperCase(b);
     74     }
     75 
     76     /**
     77      * Returns true if a and b are equal ignoring the case of the characters, including if they are
     78      * both null.
     79      * @param a first CharSequence to check
     80      * @param b second CharSequence to check
     81      * @return {@code true} if a and b are equal, {@code false} otherwise.
     82      */
     83     public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) {
     84         if (a == b)
     85             return true;  // including both a and b are null.
     86         if (a == null || b == null)
     87             return false;
     88         final int length = a.length();
     89         if (length != b.length())
     90             return false;
     91         for (int i = 0; i < length; i++) {
     92             if (!equalsIgnoreCase(a.charAt(i), b.charAt(i)))
     93                 return false;
     94         }
     95         return true;
     96     }
     97 
     98     /**
     99      * Returns true if a and b are equal ignoring the case of the characters, including if a is null
    100      * and b is zero length.
    101      * @param a CharSequence to check
    102      * @param b character array to check
    103      * @param offset start offset of array b
    104      * @param length length of characters in array b
    105      * @return {@code true} if a and b are equal, {@code false} otherwise.
    106      * @throws IndexOutOfBoundsException
    107      *   if {@code offset < 0 || length < 0 || offset + length > data.length}.
    108      * @throws NullPointerException if {@code b == null}.
    109      */
    110     public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) {
    111         if (offset < 0 || length < 0 || length > b.length - offset)
    112             throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset
    113                     + " length=" + length);
    114         if (a == null)
    115             return length == 0;  // including a is null and b is zero length.
    116         if (a.length() != length)
    117             return false;
    118         for (int i = 0; i < length; i++) {
    119             if (!equalsIgnoreCase(a.charAt(i), b[offset + i]))
    120                 return false;
    121         }
    122         return true;
    123     }
    124 
    125     /**
    126      * Returns true if cs contains any upper case characters.
    127      *
    128      * @param cs the CharSequence to check
    129      * @return {@code true} if cs contains any upper case characters, {@code false} otherwise.
    130      */
    131     public static boolean hasUpperCase(final CharSequence cs) {
    132         final int length = cs.length();
    133         for (int i = 0, cp = 0; i < length; i += Character.charCount(cp)) {
    134             cp = Character.codePointAt(cs, i);
    135             if (Character.isUpperCase(cp)) {
    136                 return true;
    137             }
    138         }
    139         return false;
    140     }
    141 
    142     /**
    143      * Remove duplicates from an array of strings.
    144      *
    145      * This method will always keep the first occurrence of all strings at their position
    146      * in the array, removing the subsequent ones.
    147      */
    148     public static void removeDupes(final ArrayList<CharSequence> suggestions) {
    149         if (suggestions.size() < 2) return;
    150         int i = 1;
    151         // Don't cache suggestions.size(), since we may be removing items
    152         while (i < suggestions.size()) {
    153             final CharSequence cur = suggestions.get(i);
    154             // Compare each suggestion with each previous suggestion
    155             for (int j = 0; j < i; j++) {
    156                 CharSequence previous = suggestions.get(j);
    157                 if (TextUtils.equals(cur, previous)) {
    158                     suggestions.remove(i);
    159                     i--;
    160                     break;
    161                 }
    162             }
    163             i++;
    164         }
    165     }
    166 
    167     public static String toTitleCase(String s, Locale locale) {
    168         if (s.length() <= 1) {
    169             // TODO: is this really correct? Shouldn't this be s.toUpperCase()?
    170             return s;
    171         }
    172         // TODO: fix the bugs below
    173         // - This does not work for Greek, because it returns upper case instead of title case.
    174         // - It does not work for Serbian, because it fails to account for the "lj" character,
    175         // which should be "Lj" in title case and "LJ" in upper case.
    176         // - It does not work for Dutch, because it fails to account for the "ij" digraph, which
    177         // are two different characters but both should be capitalized as "IJ" as if they were
    178         // a single letter.
    179         // - It also does not work with unicode surrogate code points.
    180         return s.toUpperCase(locale).charAt(0) + s.substring(1);
    181     }
    182 
    183     public static int[] toCodePointArray(final String string) {
    184         final char[] characters = string.toCharArray();
    185         final int length = characters.length;
    186         final int[] codePoints = new int[Character.codePointCount(characters, 0, length)];
    187         int codePoint = Character.codePointAt(characters, 0);
    188         int dsti = 0;
    189         for (int srci = Character.charCount(codePoint);
    190                 srci < length; srci += Character.charCount(codePoint), ++dsti) {
    191             codePoints[dsti] = codePoint;
    192             codePoint = Character.codePointAt(characters, srci);
    193         }
    194         codePoints[dsti] = codePoint;
    195         return codePoints;
    196     }
    197 }
    198