aboutsummaryrefslogtreecommitdiff
path: root/java/src/com/android/i18n/addressinput/FormatInterpreter.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/i18n/addressinput/FormatInterpreter.java')
-rw-r--r--java/src/com/android/i18n/addressinput/FormatInterpreter.java464
1 files changed, 245 insertions, 219 deletions
diff --git a/java/src/com/android/i18n/addressinput/FormatInterpreter.java b/java/src/com/android/i18n/addressinput/FormatInterpreter.java
index ed7b2ac..8634cfb 100644
--- a/java/src/com/android/i18n/addressinput/FormatInterpreter.java
+++ b/java/src/com/android/i18n/addressinput/FormatInterpreter.java
@@ -25,260 +25,286 @@ import org.json.JSONTokener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Address format interpreter. A utility to find address format related info.
*/
class FormatInterpreter {
- private static final String NEW_LINE = "%n";
+ private static final String NEW_LINE = "%n";
- private final String mDefaultFormat;
+ private final String defaultFormat;
- private final FormOptions mFormOptions;
+ private final FormOptions formOptions;
- /**
- * Creates a new instance of {@link FormatInterpreter}.
- */
- FormatInterpreter(FormOptions options) {
- Util.checkNotNull(RegionDataConstants.getCountryFormatMap(),
- "null country name map not allowed");
- Util.checkNotNull(options);
- mFormOptions = options;
- mDefaultFormat = getJsonValue("ZZ", AddressDataKey.FMT);
- Util.checkNotNull(mDefaultFormat, "null default format not allowed");
+ /**
+ * Creates a new instance of {@link FormatInterpreter}.
+ */
+ FormatInterpreter(FormOptions options) {
+ Util.checkNotNull(RegionDataConstants.getCountryFormatMap(),
+ "null country name map not allowed");
+ Util.checkNotNull(options);
+ formOptions = options;
+ defaultFormat = getJsonValue("ZZ", AddressDataKey.FMT);
+ Util.checkNotNull(defaultFormat, "null default format not allowed");
+ }
+
+ /**
+ * Returns a list of address fields based on the format of {@code regionCode}. Script type is
+ * needed because some countries uses different address formats for local/Latin scripts.
+ *
+ * @param scriptType if {@link ScriptType#LOCAL}, use local format; else use Latin format.
+ */
+ List<AddressField> getAddressFieldOrder(ScriptType scriptType, String regionCode) {
+ Util.checkNotNull(scriptType);
+ Util.checkNotNull(regionCode);
+ List<AddressField> fieldOrder = new ArrayList<AddressField>();
+ for (String substring : getFormatSubStrings(scriptType, regionCode)) {
+ // Skips un-escaped characters and new lines.
+ if (!substring.matches("%.") || substring.equals(NEW_LINE)) {
+ continue;
+ }
+
+ AddressField field = AddressField.of(substring.charAt(1));
+ fieldOrder.add(field);
}
- /**
- * Returns a list of address fields based on the format of {@code regionCode}. Script type is
- * needed because some countries uses different address formats for local/Latin scripts.
- *
- * @param scriptType if {@link ScriptType#LOCAL}, use local format; else use Latin format.
- */
- List<AddressField> getAddressFieldOrder(ScriptType scriptType, String regionCode) {
- Util.checkNotNull(scriptType);
- Util.checkNotNull(regionCode);
- List<AddressField> fieldOrder = new ArrayList<AddressField>();
- for (String substring : getFormatSubStrings(scriptType, regionCode)) {
- // Skips un-escaped characters and new lines.
- if (!substring.matches("%.") || substring.equals(NEW_LINE)) {
- continue;
- }
-
- AddressField field = AddressField.of(substring.charAt(1));
- fieldOrder.add(field);
- }
+ overrideFieldOrder(regionCode, fieldOrder);
- overrideFieldOrder(regionCode, fieldOrder);
-
- // Uses two address lines instead of street address.
- List<AddressField> finalFieldOrder = new ArrayList<AddressField>();
- for (AddressField field : fieldOrder) {
- if (field == AddressField.STREET_ADDRESS) {
- finalFieldOrder.add(AddressField.ADDRESS_LINE_1);
- finalFieldOrder.add(AddressField.ADDRESS_LINE_2);
- } else {
- finalFieldOrder.add(field);
- }
- }
- return finalFieldOrder;
+ // Uses two address lines instead of street address.
+ List<AddressField> finalFieldOrder = new ArrayList<AddressField>();
+ for (AddressField field : fieldOrder) {
+ if (field == AddressField.STREET_ADDRESS) {
+ finalFieldOrder.add(AddressField.ADDRESS_LINE_1);
+ finalFieldOrder.add(AddressField.ADDRESS_LINE_2);
+ } else {
+ finalFieldOrder.add(field);
+ }
}
+ return finalFieldOrder;
+ }
- /**
- * Returns a list of address fields based on the format of {@code regionCode} -- assuming script
- * type is {@link ScriptType#LOCAL}.
- */
- List<AddressField> getAddressFieldOrder(String regionCode) {
- Util.checkNotNull(regionCode);
- return getAddressFieldOrder(ScriptType.LOCAL, regionCode);
+ /**
+ * Returns a list of address fields based on the format of {@code regionCode} -- assuming script
+ * type is {@link ScriptType#LOCAL}.
+ */
+ List<AddressField> getAddressFieldOrder(String regionCode) {
+ Util.checkNotNull(regionCode);
+ return getAddressFieldOrder(ScriptType.LOCAL, regionCode);
+ }
+
+ private void overrideFieldOrder(String regionCode, List<AddressField> fieldOrder) {
+ if (formOptions.getCustomFieldOrder(regionCode) == null) {
+ return;
}
- private void overrideFieldOrder(String regionCode, List<AddressField> fieldOrder) {
- if (mFormOptions.getCustomFieldOrder(regionCode) == null) {
- return;
- }
+ // Constructs a hash for overridden field order.
+ final Map<AddressField, Integer> fieldPriority = new HashMap<AddressField, Integer>();
+ int i = 0;
+ for (AddressField field : formOptions.getCustomFieldOrder(regionCode)) {
+ fieldPriority.put(field, i);
+ i++;
+ }
- // Constructs a hash for overridden field order.
- final Map<AddressField, Integer> fieldPriority = new HashMap<AddressField, Integer>();
- int i = 0;
- for (AddressField field : mFormOptions.getCustomFieldOrder(regionCode)) {
- fieldPriority.put(field, i);
- i++;
- }
+ // Finds union of input fields and priority list.
+ List<AddressField> union = new ArrayList<AddressField>();
+ List<Integer> slots = new ArrayList<Integer>();
+ i = 0;
+ for (AddressField field : fieldOrder) {
+ if (fieldPriority.containsKey(field)) {
+ union.add(field);
+ slots.add(i);
+ }
+ i++;
+ }
- // Finds union of input fields and priority list.
- List<AddressField> union = new ArrayList<AddressField>();
- List<Integer> slots = new ArrayList<Integer>();
- i = 0;
- for (AddressField field : fieldOrder) {
- if (fieldPriority.containsKey(field)) {
- union.add(field);
- slots.add(i);
- }
- i++;
- }
+ // Overrides field order with priority list.
+ Collections.sort(union, new Comparator<AddressField>() {
+ @Override
+ public int compare(AddressField o1, AddressField o2) {
+ return fieldPriority.get(o1) - fieldPriority.get(o2);
+ }
+ });
- // Overrides field order with priority list.
- Collections.sort(union, new Comparator<AddressField>() {
- @Override
- public int compare(AddressField o1, AddressField o2) {
- return fieldPriority.get(o1) - fieldPriority.get(o2);
- }
- });
-
- // Puts reordered fields in slots.
- for (int j = 0; j < union.size(); ++j) {
- fieldOrder.set(slots.get(j), union.get(j));
- }
+ // Puts reordered fields in slots.
+ for (int j = 0; j < union.size(); ++j) {
+ fieldOrder.set(slots.get(j), union.get(j));
+ }
+ }
+
+ /**
+ * Returns the fields that are required to be filled in for this country. This is based upon the
+ * "required" field in RegionDataConstants for {@code regionCode}, and handles falling back to
+ * the default data if necessary.
+ */
+ static Set<AddressField> getRequiredFields(String regionCode) {
+ Util.checkNotNull(regionCode);
+ String requireString = getRequiredString(regionCode);
+
+ EnumSet<AddressField> required = EnumSet.of(AddressField.COUNTRY);
+ for (char c : requireString.toCharArray()) {
+ required.add(AddressField.of(c));
}
+ return required;
+ }
- /**
- * Gets formatted address. For example,
- *
- * <p> John Doe<br> Dnar Corp<br> 5th St<br> Santa Monica CA 90123 </p>
- *
- * This method does not validate addresses. Also, it will "normalize" the result strings by
- * removing redundant spaces and empty lines.
- */
- List<String> getEnvelopeAddress(AddressData address) {
- Util.checkNotNull(address, "null input address not allowed");
- String regionCode = address.getPostalCountry();
-
- String lc = address.getLanguageCode();
- ScriptType scriptType = ScriptType.LOCAL;
- if (lc != null) {
- scriptType = Util.isExplicitLatinScript(lc) ? ScriptType.LATIN : ScriptType.LOCAL;
+ private static String getRequiredString(String regionCode) {
+ String required = getJsonValue(regionCode, AddressDataKey.REQUIRE);
+ if (required == null) {
+ required = getJsonValue("ZZ", AddressDataKey.REQUIRE);
+ }
+ return required;
+ }
+
+ /**
+ * Gets formatted address. For example,
+ *
+ * <p> John Doe<br> Dnar Corp<br> 5th St<br> Santa Monica CA 90123 </p>
+ *
+ * This method does not validate addresses. Also, it will "normalize" the result strings by
+ * removing redundant spaces and empty lines.
+ */
+ List<String> getEnvelopeAddress(AddressData address) {
+ Util.checkNotNull(address, "null input address not allowed");
+ String regionCode = address.getPostalCountry();
+
+ String lc = address.getLanguageCode();
+ ScriptType scriptType = ScriptType.LOCAL;
+ if (lc != null) {
+ scriptType = Util.isExplicitLatinScript(lc) ? ScriptType.LATIN : ScriptType.LOCAL;
+ }
+
+ List<String> lines = new ArrayList<String>();
+ StringBuilder currentLine = new StringBuilder();
+ for (String formatSymbol : getFormatSubStrings(scriptType, regionCode)) {
+ if (formatSymbol.equals(NEW_LINE)) {
+ String normalizedStr =
+ removeRedundantSpacesAndLeadingPunctuation(currentLine.toString());
+ if (normalizedStr.length() > 0) {
+ lines.add(normalizedStr);
+ currentLine.setLength(0);
}
+ } else if (formatSymbol.startsWith("%")) {
+ char c = formatSymbol.charAt(1);
+ AddressField field = AddressField.of(c);
+ Util.checkNotNull(field, "null address field for character " + c);
- List<String> lines = new ArrayList<String>();
- StringBuilder currentLine = new StringBuilder();
- for (String formatSymbol : getFormatSubStrings(scriptType, regionCode)) {
- if (formatSymbol.equals(NEW_LINE)) {
- String normalizedStr =
- removeRedundantSpacesAndLeadingPunctuation(currentLine.toString());
- if (normalizedStr.length() > 0) {
- lines.add(normalizedStr);
- currentLine.setLength(0);
- }
- } else if (formatSymbol.startsWith("%")) {
- char c = formatSymbol.charAt(1);
- AddressField field = AddressField.of(c);
- Util.checkNotNull(field, "null address field for character " + c);
-
- String value = null;
- switch (field) {
- case STREET_ADDRESS:
- value = Util.joinAndSkipNulls("\n",
- address.getAddressLine1(),
- address.getAddressLine2());
- break;
- case COUNTRY:
- // Country name is treated separately.
- break;
- case ADMIN_AREA:
- value = address.getAdministrativeArea();
- break;
- case LOCALITY:
- value = address.getLocality();
- break;
- case DEPENDENT_LOCALITY:
- value = address.getDependentLocality();
- break;
- case RECIPIENT:
- value = address.getRecipient();
- break;
- case ORGANIZATION:
- value = address.getOrganization();
- break;
- case POSTAL_CODE:
- value = address.getPostalCode();
- break;
- default:
- break;
- }
-
- if (value != null) {
- currentLine.append(value);
- }
- } else {
- currentLine.append(formatSymbol);
- }
+ String value = null;
+ switch (field) {
+ case STREET_ADDRESS:
+ value = Util.joinAndSkipNulls("\n",
+ address.getAddressLine1(),
+ address.getAddressLine2());
+ break;
+ case COUNTRY:
+ // Country name is treated separately.
+ break;
+ case ADMIN_AREA:
+ value = address.getAdministrativeArea();
+ break;
+ case LOCALITY:
+ value = address.getLocality();
+ break;
+ case DEPENDENT_LOCALITY:
+ value = address.getDependentLocality();
+ break;
+ case RECIPIENT:
+ value = address.getRecipient();
+ break;
+ case ORGANIZATION:
+ value = address.getOrganization();
+ break;
+ case POSTAL_CODE:
+ value = address.getPostalCode();
+ break;
+ default:
+ break;
}
- String normalizedStr = removeRedundantSpacesAndLeadingPunctuation(currentLine.toString());
- if (normalizedStr.length() > 0) {
- lines.add(normalizedStr);
+
+ if (value != null) {
+ currentLine.append(value);
}
- return lines;
+ } else {
+ currentLine.append(formatSymbol);
+ }
+ }
+ String normalizedStr = removeRedundantSpacesAndLeadingPunctuation(currentLine.toString());
+ if (normalizedStr.length() > 0) {
+ lines.add(normalizedStr);
}
+ return lines;
+ }
- /**
- * Tokenizes the format string and returns the token string list. "%" is treated as an escape
- * character. So for example "%n%a%nxyz" will be split into "%n", "%a", "%n", "x", "y", and "z".
- * Escaped tokens correspond to either new line or address fields.
- */
- private List<String> getFormatSubStrings(ScriptType scriptType, String regionCode) {
- String formatString = getFormatString(scriptType, regionCode);
- List<String> parts = new ArrayList<String>();
-
- boolean escaped = false;
- for (char c : formatString.toCharArray()) {
- if (escaped) {
- escaped = false;
- if (NEW_LINE.equals("%" + c)) {
- parts.add(NEW_LINE);
- } else {
- Util.checkNotNull(AddressField.of(c), "Unrecognized character '" + c
- + "' in format pattern: " + formatString);
- parts.add("%" + c);
- }
- } else if (c == '%') {
- escaped = true;
- } else {
- parts.add(c + "");
- }
+ /**
+ * Tokenizes the format string and returns the token string list. "%" is treated as an escape
+ * character. So for example "%n%a%nxyz" will be split into "%n", "%a", "%n", "x", "y", and "z".
+ * Escaped tokens correspond to either new line or address fields.
+ */
+ private List<String> getFormatSubStrings(ScriptType scriptType, String regionCode) {
+ String formatString = getFormatString(scriptType, regionCode);
+ List<String> parts = new ArrayList<String>();
+
+ boolean escaped = false;
+ for (char c : formatString.toCharArray()) {
+ if (escaped) {
+ escaped = false;
+ if (NEW_LINE.equals("%" + c)) {
+ parts.add(NEW_LINE);
+ } else {
+ Util.checkNotNull(AddressField.of(c), "Unrecognized character '" + c
+ + "' in format pattern: " + formatString);
+ parts.add("%" + c);
}
- return parts;
+ } else if (c == '%') {
+ escaped = true;
+ } else {
+ parts.add(c + "");
+ }
}
+ return parts;
+ }
- private static String removeRedundantSpacesAndLeadingPunctuation(String str) {
- // Remove leading commas and other punctuation that might have been added by the formatter
- // in the case of missing data.
- str = str.replaceFirst("^[-,\\s]+", "");
- str = str.trim();
- str = str.replaceAll(" +", " ");
- return str;
- }
+ private static String removeRedundantSpacesAndLeadingPunctuation(String str) {
+ // Remove leading commas and other punctuation that might have been added by the formatter
+ // in the case of missing data.
+ str = str.replaceFirst("^[-,\\s]+", "");
+ str = str.trim();
+ str = str.replaceAll(" +", " ");
+ return str;
+ }
- private static String getFormatString(ScriptType scriptType, String regionCode) {
- String format = (scriptType == ScriptType.LOCAL)
- ? getJsonValue(regionCode, AddressDataKey.FMT)
- : getJsonValue(regionCode, AddressDataKey.LFMT);
- if (format == null) {
- format = getJsonValue("ZZ", AddressDataKey.FMT);
- }
- return format;
+ private static String getFormatString(ScriptType scriptType, String regionCode) {
+ String format = (scriptType == ScriptType.LOCAL)
+ ? getJsonValue(regionCode, AddressDataKey.FMT)
+ : getJsonValue(regionCode, AddressDataKey.LFMT);
+ if (format == null) {
+ format = getJsonValue("ZZ", AddressDataKey.FMT);
}
+ return format;
+ }
- private static String getJsonValue(String regionCode, AddressDataKey key) {
- Util.checkNotNull(regionCode);
- String jsonString = RegionDataConstants.getCountryFormatMap().get(regionCode);
- Util.checkNotNull(jsonString, "no json data for region code " + regionCode);
-
- try {
- JSONObject jsonObj = new JSONObject(new JSONTokener(jsonString));
- if (!jsonObj.has(key.name().toLowerCase())) {
- // Key not found. Return null.
- return null;
- }
- // Gets the string for this key.
- String parsedJsonString = jsonObj.getString(key.name().toLowerCase());
- return parsedJsonString;
- } catch (JSONException e) {
- throw new RuntimeException("Invalid json for region code " + regionCode
- + ": " + jsonString);
- }
+ private static String getJsonValue(String regionCode, AddressDataKey key) {
+ Util.checkNotNull(regionCode);
+ String jsonString = RegionDataConstants.getCountryFormatMap().get(regionCode);
+ Util.checkNotNull(jsonString, "no json data for region code " + regionCode);
+
+ try {
+ JSONObject jsonObj = new JSONObject(new JSONTokener(jsonString));
+ if (!jsonObj.has(key.name().toLowerCase())) {
+ // Key not found. Return null.
+ return null;
+ }
+ // Gets the string for this key.
+ String parsedJsonString = jsonObj.getString(key.name().toLowerCase());
+ return parsedJsonString;
+ } catch (JSONException e) {
+ throw new RuntimeException("Invalid json for region code " + regionCode
+ + ": " + jsonString);
}
+ }
}