aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java82
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java4
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java4
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java2
-rw-r--r--java/src/com/android/inputmethod/latin/StringUtils.java38
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