diff options
Diffstat (limited to 'java/src')
5 files changed, 70 insertions, 60 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index b1813a141..ba449eeb3 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -53,7 +53,9 @@ public final class KeySpecParser { private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; // Constants for parsing. - private static final char LABEL_END = '|'; + private static final char COMMA = ','; + private static final char BACKSLASH = '\\'; + private static final char VERTICAL_BAR = '|'; private static final String PREFIX_TEXT = "!text/"; static final String PREFIX_ICON = "!icon/"; private static final String PREFIX_CODE = "!code/"; @@ -64,6 +66,59 @@ public final class KeySpecParser { // Intentional empty constructor for utility class. } + /** + * Split the text containing multiple key specifications separated by commas into an array of + * key specifications. + * A key specification can contain a character escaped by the backslash character, including a + * comma character. + * Note that an empty key specification will be eliminated from the result array. + * + * @param text the text containing multiple key specifications. + * @return an array of key specification text. Null if the specified <code>text</code> is empty + * or has no key specifications. + */ + public static String[] splitKeySpecs(final String text) { + final int size = text.length(); + if (size == 0) { + return null; + } + // Optimization for one-letter key specification. + if (size == 1) { + return text.charAt(0) == COMMA ? null : new String[] { text }; + } + + ArrayList<String> list = null; + int start = 0; + // The characters in question in this loop are COMMA and BACKSLASH. These characters never + // match any high or low surrogate character. So it is OK to iterate through with char + // index. + for (int pos = 0; pos < size; pos++) { + final char c = text.charAt(pos); + if (c == COMMA) { + // 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 == BACKSLASH) { + // 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()]); + } + private static boolean hasIcon(final String moreKeySpec) { return moreKeySpec.startsWith(PREFIX_ICON); } @@ -78,14 +133,14 @@ public final class KeySpecParser { } private static String parseEscape(final String text) { - if (text.indexOf(Constants.CSV_ESCAPE) < 0) { + if (text.indexOf(BACKSLASH) < 0) { return text; } final int length = text.length(); final StringBuilder sb = new StringBuilder(); for (int pos = 0; pos < length; pos++) { final char c = text.charAt(pos); - if (c == Constants.CSV_ESCAPE && pos + 1 < length) { + if (c == BACKSLASH && pos + 1 < length) { // Skip escape char pos++; sb.append(text.charAt(pos)); @@ -97,20 +152,20 @@ public final class KeySpecParser { } private static int indexOfLabelEnd(final String moreKeySpec, final int start) { - if (moreKeySpec.indexOf(Constants.CSV_ESCAPE, start) < 0) { - final int end = moreKeySpec.indexOf(LABEL_END, start); + if (moreKeySpec.indexOf(BACKSLASH, start) < 0) { + final int end = moreKeySpec.indexOf(VERTICAL_BAR, start); if (end == 0) { - throw new KeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec); + throw new KeySpecParserError(VERTICAL_BAR + " at " + start + ": " + moreKeySpec); } return end; } final int length = moreKeySpec.length(); for (int pos = start; pos < length; pos++) { final char c = moreKeySpec.charAt(pos); - if (c == Constants.CSV_ESCAPE && pos + 1 < length) { + if (c == BACKSLASH && pos + 1 < length) { // Skip escape char pos++; - } else if (c == LABEL_END) { + } else if (c == VERTICAL_BAR) { return pos; } } @@ -136,9 +191,9 @@ public final class KeySpecParser { return null; } if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { - throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); + throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); } - return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1)); + return parseEscape(moreKeySpec.substring(end + /* VERTICAL_BAR */1)); } static String getOutputText(final String moreKeySpec) { @@ -169,7 +224,7 @@ public final class KeySpecParser { if (hasCode(moreKeySpec)) { final int end = indexOfLabelEnd(moreKeySpec, 0); if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { - throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); + throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); } return parseCode(moreKeySpec.substring(end + 1), codesSet, CODE_UNSPECIFIED); } @@ -204,7 +259,7 @@ public final class KeySpecParser { public static int getIconId(final String moreKeySpec) { if (moreKeySpec != null && hasIcon(moreKeySpec)) { - final int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length()); + final int end = moreKeySpec.indexOf(VERTICAL_BAR, PREFIX_ICON.length()); final String name = (end < 0) ? moreKeySpec.substring(PREFIX_ICON.length()) : moreKeySpec.substring(PREFIX_ICON.length(), end); return KeyboardIconsSet.getIconId(name); @@ -351,7 +406,7 @@ public final class KeySpecParser { final String name = text.substring(pos + prefixLen, end); sb.append(textsSet.getText(name)); pos = end - 1; - } else if (c == Constants.CSV_ESCAPE) { + } else if (c == BACKSLASH) { if (sb != null) { // Append both escape character and escaped character. sb.append(text.substring(pos, Math.min(pos + 2, size))); @@ -366,7 +421,6 @@ public final class KeySpecParser { text = sb.toString(); } } while (sb != null); - return text; } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java index 5db3ebbd1..f65056948 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java @@ -18,8 +18,6 @@ package com.android.inputmethod.keyboard.internal; import android.content.res.TypedArray; -import com.android.inputmethod.latin.StringUtils; - public abstract class KeyStyle { private final KeyboardTextsSet mTextsSet; @@ -42,7 +40,7 @@ public abstract class KeyStyle { protected String[] parseStringArray(final TypedArray a, final int index) { if (a.hasValue(index)) { final String text = KeySpecParser.resolveTextReference(a.getString(index), mTextsSet); - return StringUtils.parseCsvString(text); + return KeySpecParser.splitKeySpecs(text); } return null; } diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 86bb25562..64c14d32f 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -215,10 +215,6 @@ public final class Constants { } } - // Constants for CSV parsing. - public static final char CSV_SEPARATOR = ','; - public static final char CSV_ESCAPE = '\\'; - private Constants() { // This utility class is not publicly instantiable. } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 1ad8def16..09102447f 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -100,7 +100,7 @@ public final class SettingsValues { mWordConnectors = StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors)); Arrays.sort(mWordConnectors); - final String[] suggestPuncsSpec = StringUtils.parseCsvString(res.getString( + final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString( R.string.suggested_punctuations)); mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); mWordSeparators = res.getString(R.string.symbols_word_separators); diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 988b7f60e..c2fd4fb32 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -153,44 +153,6 @@ public final class StringUtils { return codePoints; } - 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()]); - } - // This method assumes the text is not null. For the empty string, it returns CAPITALIZE_NONE. public static int getCapitalizationType(final String text) { // If the first char is not uppercase, then the word is either all lower case or |