1cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka/*
2cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project
3cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka *
4cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
5cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * you may not use this file except in compliance with the License.
6cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * You may obtain a copy of the License at
7cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka *
8cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka *
10cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
11cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
12cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * See the License for the specific language governing permissions and
14cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka * limitations under the License.
15cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka */
16cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
17cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokapackage com.android.inputmethod.latin;
18cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
19cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokaimport android.text.TextUtils;
20cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
21cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokaimport java.util.ArrayList;
2211d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaokaimport java.util.Locale;
23cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
24cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokapublic class StringUtils {
25cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    private StringUtils() {
26cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        // This utility class is not publicly instantiable.
27cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
28cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
29cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    public static int codePointCount(String text) {
30cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
31cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        return text.codePointCount(0, text.length());
32cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
33cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
34344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka    public static boolean containsInArray(String key, String[] array) {
35344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        for (final String element : array) {
36344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka            if (key.equals(element)) return true;
37cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        }
38cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        return false;
39cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
40cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
41344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka    public static boolean containsInCsv(String key, String csv) {
42344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        if (TextUtils.isEmpty(csv)) return false;
43344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        return containsInArray(key, csv.split(","));
44344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka    }
45344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka
46344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka    public static String appendToCsvIfNotExists(String key, String csv) {
47344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        if (TextUtils.isEmpty(csv)) return key;
48344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        if (containsInCsv(key, csv)) return csv;
49344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        return csv + "," + key;
50344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka    }
51344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka
52344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka    public static String removeFromCsvIfExists(String key, String csv) {
53344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        if (TextUtils.isEmpty(csv)) return "";
54344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        final String[] elements = csv.split(",");
55344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        if (!containsInArray(key, elements)) return csv;
56344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        final ArrayList<String> result = new ArrayList<String>(elements.length - 1);
57344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        for (final String element : elements) {
58344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka            if (!key.equals(element)) result.add(element);
59344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        }
60344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka        return TextUtils.join(",", result);
61cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
62cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
63cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    /**
64cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * Returns true if a and b are equal ignoring the case of the character.
65cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param a first character to check
66cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param b second character to check
67cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @return {@code true} if a and b are equal, {@code false} otherwise.
68cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     */
69cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    public static boolean equalsIgnoreCase(char a, char b) {
70cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        // Some language, such as Turkish, need testing both cases.
71cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        return a == b
72cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                || Character.toLowerCase(a) == Character.toLowerCase(b)
73cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                || Character.toUpperCase(a) == Character.toUpperCase(b);
74cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
75cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
76cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    /**
77cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * Returns true if a and b are equal ignoring the case of the characters, including if they are
78cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * both null.
79cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param a first CharSequence to check
80cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param b second CharSequence to check
81cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @return {@code true} if a and b are equal, {@code false} otherwise.
82cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     */
83cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) {
84cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (a == b)
85cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            return true;  // including both a and b are null.
86cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (a == null || b == null)
87cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            return false;
88cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        final int length = a.length();
89cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (length != b.length())
90cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            return false;
91cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        for (int i = 0; i < length; i++) {
92cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            if (!equalsIgnoreCase(a.charAt(i), b.charAt(i)))
93cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                return false;
94cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        }
95cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        return true;
96cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
97cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
98cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    /**
99cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * Returns true if a and b are equal ignoring the case of the characters, including if a is null
100cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * and b is zero length.
101cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param a CharSequence to check
102cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param b character array to check
103cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param offset start offset of array b
104cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @param length length of characters in array b
105cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @return {@code true} if a and b are equal, {@code false} otherwise.
106cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @throws IndexOutOfBoundsException
107cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     *   if {@code offset < 0 || length < 0 || offset + length > data.length}.
108cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * @throws NullPointerException if {@code b == null}.
109cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     */
110cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) {
111cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (offset < 0 || length < 0 || length > b.length - offset)
112cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset
113cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                    + " length=" + length);
114cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (a == null)
115cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            return length == 0;  // including a is null and b is zero length.
116cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (a.length() != length)
117cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            return false;
118cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        for (int i = 0; i < length; i++) {
119cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            if (!equalsIgnoreCase(a.charAt(i), b[offset + i]))
120cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                return false;
121cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        }
122cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        return true;
123cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
124cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka
125cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    /**
1260806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang     * Returns true if cs contains any upper case characters.
1270806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang     *
1280806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang     * @param cs the CharSequence to check
1290806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang     * @return {@code true} if cs contains any upper case characters, {@code false} otherwise.
1300806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang     */
1310806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang    public static boolean hasUpperCase(final CharSequence cs) {
1320806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang        final int length = cs.length();
1330806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang        for (int i = 0, cp = 0; i < length; i += Character.charCount(cp)) {
1340806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang            cp = Character.codePointAt(cs, i);
1350806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang            if (Character.isUpperCase(cp)) {
1360806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang                return true;
1370806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang            }
1380806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang        }
1390806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang        return false;
1400806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang    }
1410806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang
1420806bb01d9e857db9fbac38b9b6e77feb9e9e4c9Tom Ouyang    /**
143cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * Remove duplicates from an array of strings.
144cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     *
145a4c7733cf7b5c0f970d1a8e52ee52b6199f56031Tadashi G. Takaoka     * This method will always keep the first occurrence of all strings at their position
146cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     * in the array, removing the subsequent ones.
147cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka     */
148cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    public static void removeDupes(final ArrayList<CharSequence> suggestions) {
149cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        if (suggestions.size() < 2) return;
150cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        int i = 1;
151cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        // Don't cache suggestions.size(), since we may be removing items
152cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        while (i < suggestions.size()) {
153cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            final CharSequence cur = suggestions.get(i);
154cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            // Compare each suggestion with each previous suggestion
155cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            for (int j = 0; j < i; j++) {
156cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                CharSequence previous = suggestions.get(j);
157cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                if (TextUtils.equals(cur, previous)) {
158adf218eed544f2239ca5394b8a6bcc542d89a4d9Jean Chalard                    suggestions.remove(i);
159cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                    i--;
160cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                    break;
161cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                }
162cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            }
163cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka            i++;
164cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka        }
165cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka    }
16611d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka
16711d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka    public static String toTitleCase(String s, Locale locale) {
16811d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        if (s.length() <= 1) {
16911d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka            // TODO: is this really correct? Shouldn't this be s.toUpperCase()?
17011d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka            return s;
17111d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        }
17211d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // TODO: fix the bugs below
17311d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // - This does not work for Greek, because it returns upper case instead of title case.
17411d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // - It does not work for Serbian, because it fails to account for the "lj" character,
17511d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // which should be "Lj" in title case and "LJ" in upper case.
17611d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // - It does not work for Dutch, because it fails to account for the "ij" digraph, which
17711d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // are two different characters but both should be capitalized as "IJ" as if they were
17811d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // a single letter.
17911d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        // - It also does not work with unicode surrogate code points.
18011d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka        return s.toUpperCase(locale).charAt(0) + s.substring(1);
18111d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka    }
18280111f08e284655808380663f0b68547b981da72Jean Chalard
18380111f08e284655808380663f0b68547b981da72Jean Chalard    public static int[] toCodePointArray(final String string) {
18480111f08e284655808380663f0b68547b981da72Jean Chalard        final char[] characters = string.toCharArray();
18580111f08e284655808380663f0b68547b981da72Jean Chalard        final int length = characters.length;
18680111f08e284655808380663f0b68547b981da72Jean Chalard        final int[] codePoints = new int[Character.codePointCount(characters, 0, length)];
18780111f08e284655808380663f0b68547b981da72Jean Chalard        int codePoint = Character.codePointAt(characters, 0);
18880111f08e284655808380663f0b68547b981da72Jean Chalard        int dsti = 0;
18980111f08e284655808380663f0b68547b981da72Jean Chalard        for (int srci = Character.charCount(codePoint);
19080111f08e284655808380663f0b68547b981da72Jean Chalard                srci < length; srci += Character.charCount(codePoint), ++dsti) {
19180111f08e284655808380663f0b68547b981da72Jean Chalard            codePoints[dsti] = codePoint;
19280111f08e284655808380663f0b68547b981da72Jean Chalard            codePoint = Character.codePointAt(characters, srci);
19380111f08e284655808380663f0b68547b981da72Jean Chalard        }
19480111f08e284655808380663f0b68547b981da72Jean Chalard        codePoints[dsti] = codePoint;
19580111f08e284655808380663f0b68547b981da72Jean Chalard        return codePoints;
19680111f08e284655808380663f0b68547b981da72Jean Chalard    }
197cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka}
198