Browse Source

Improve performance of AsYouTypeFormatter by precompliling regular expressions and decrease object allocation by reusing StringBuffers.

pull/567/head
Shaopeng Jia 16 years ago
committed by Mihaela Rosca
parent
commit
a6e28fee08
2 changed files with 21 additions and 17 deletions
  1. +16
    -14
      java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
  2. +5
    -3
      java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java

+ 16
- 14
java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java View File

@ -58,7 +58,9 @@ public class AsYouTypeFormatter {
private Pattern internationalPrefix; private Pattern internationalPrefix;
private StringBuffer prefixBeforeNationalNumber; private StringBuffer prefixBeforeNationalNumber;
private StringBuffer nationalNumber; private StringBuffer nationalNumber;
private static Pattern UNSUPPORTED_SYNTAX_PATTERN = Pattern.compile("\\|");
private final Pattern UNSUPPORTED_SYNTAX = Pattern.compile("[*#;,a-zA-Z]");
private final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]");
private final Pattern STANDALONE_DIGIT_PATTERN = Pattern.compile("\\d(?=[^,}][^,}])");
/** /**
* Constructs a light-weight formatter which does no formatting, but outputs exactly what is * Constructs a light-weight formatter which does no formatting, but outputs exactly what is
@ -125,17 +127,16 @@ public class AsYouTypeFormatter {
String numberPattern = format.getPattern(); String numberPattern = format.getPattern();
// The formatter doesn't format numbers when numberPattern contains "|", e.g. // The formatter doesn't format numbers when numberPattern contains "|", e.g.
// (20|3)\d{4,5}. In those cases we quickly return.
Matcher unsupportedSyntax = UNSUPPORTED_SYNTAX_PATTERN.matcher(numberPattern);
if (unsupportedSyntax.find()) {
// (20|3)\d{4}. In those cases we quickly return.
if (numberPattern.indexOf('|') != -1) {
return false; return false;
} }
// Replace anything in the form of [..] with \d // Replace anything in the form of [..] with \d
numberPattern = numberPattern.replaceAll("\\[([^\\[\\]])*\\]","\\\\d");
numberPattern = CHARACTER_CLASS_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
// Replace any standalone digit (not the one in d{}) with \d // Replace any standalone digit (not the one in d{}) with \d
numberPattern = numberPattern.replaceAll("\\d(?=[^,}])", "\\\\d");
numberPattern = STANDALONE_DIGIT_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
formattingTemplate = getFormattingTemplate(numberPattern, numberFormat); formattingTemplate = getFormattingTemplate(numberPattern, numberFormat);
return true; return true;
@ -161,12 +162,12 @@ public class AsYouTypeFormatter {
* Clears the internal state of the formatter, so it could be reused. * Clears the internal state of the formatter, so it could be reused.
*/ */
public void clear() { public void clear() {
accruedInput = new StringBuffer();
accruedInputWithoutFormatting = new StringBuffer();
currentOutput = new StringBuffer();
accruedInput.setLength(0);
accruedInputWithoutFormatting.setLength(0);
currentOutput.setLength(0);
lastMatchPosition = 0; lastMatchPosition = 0;
prefixBeforeNationalNumber = new StringBuffer();
nationalNumber = new StringBuffer();
prefixBeforeNationalNumber.setLength(0);
nationalNumber.setLength(0);
ableToFormat = true; ableToFormat = true;
isInternationalFormatting = false; isInternationalFormatting = false;
if (!currentMetaData.equals(defaultMetaData)) { if (!currentMetaData.equals(defaultMetaData)) {
@ -185,7 +186,7 @@ public class AsYouTypeFormatter {
public String inputDigit(char nextChar) { public String inputDigit(char nextChar) {
accruedInput.append(nextChar); accruedInput.append(nextChar);
// * and # are normally used in mobile codes, which we do not format. // * and # are normally used in mobile codes, which we do not format.
if (nextChar == '*' || nextChar == '#' || Character.isLetter(nextChar)) {
if (UNSUPPORTED_SYNTAX.matcher(Character.toString(nextChar)).matches()) {
ableToFormat = false; ableToFormat = false;
} }
if (!ableToFormat) { if (!ableToFormat) {
@ -269,7 +270,7 @@ public class AsYouTypeFormatter {
* It returns true for all other cases. * It returns true for all other cases.
*/ */
private boolean extractIddAndValidCountryCode() { private boolean extractIddAndValidCountryCode() {
nationalNumber = new StringBuffer();
nationalNumber.setLength(0);
Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting); Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
if (iddMatcher.lookingAt()) { if (iddMatcher.lookingAt()) {
isInternationalFormatting = true; isInternationalFormatting = true;
@ -292,7 +293,8 @@ public class AsYouTypeFormatter {
prefixBeforeNationalNumber.append(countryCode).append(" "); prefixBeforeNationalNumber.append(countryCode).append(" ");
} }
} else { } else {
nationalNumber = new StringBuffer(accruedInputWithoutFormatting);
nationalNumber.setLength(0);
nationalNumber.append(accruedInputWithoutFormatting);
} }
return true; return true;
} }


+ 5
- 3
java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java View File

@ -63,7 +63,9 @@ public class AsYouTypeFormatterTest extends TestCase {
assertEquals("650 253 2", formatter.inputDigit('2')); assertEquals("650 253 2", formatter.inputDigit('2'));
assertEquals("650 253 22", formatter.inputDigit('2')); assertEquals("650 253 22", formatter.inputDigit('2'));
assertEquals("650 253 222", formatter.inputDigit('2')); assertEquals("650 253 222", formatter.inputDigit('2'));
assertEquals("650 253 2222", formatter.inputDigit('2'));
// No more formatting when semicolon is entered.
assertEquals("650253222;", formatter.inputDigit(';'));
assertEquals("650253222;2", formatter.inputDigit('2'));
formatter.clear(); formatter.clear();
assertEquals("6", formatter.inputDigit('6')); assertEquals("6", formatter.inputDigit('6'));
@ -191,7 +193,7 @@ public class AsYouTypeFormatterTest extends TestCase {
assertEquals("800 MY AP", formatter.inputDigit('P')); assertEquals("800 MY AP", formatter.inputDigit('P'));
assertEquals("800 MY APP", formatter.inputDigit('P')); assertEquals("800 MY APP", formatter.inputDigit('P'));
assertEquals("800 MY APPL", formatter.inputDigit('L')); assertEquals("800 MY APPL", formatter.inputDigit('L'));
assertEquals("800 MY APPLE", formatter.inputDigit('E'));
assertEquals("800 MY APPLE", formatter.inputDigit('E'));
} }
public void testAsYouTypeFormatterGBFixedLine() { public void testAsYouTypeFormatterGBFixedLine() {
@ -260,7 +262,7 @@ public class AsYouTypeFormatterTest extends TestCase {
assertEquals("0301", formatter.inputDigit('1')); assertEquals("0301", formatter.inputDigit('1'));
assertEquals("03012", formatter.inputDigit('2')); assertEquals("03012", formatter.inputDigit('2'));
assertEquals("030 123", formatter.inputDigit('3')); assertEquals("030 123", formatter.inputDigit('3'));
assertEquals("030 1234", formatter.inputDigit('4'));
assertEquals("030 1234", formatter.inputDigit('4'));
} }
public void testAsYouTypeFormatterAR() { public void testAsYouTypeFormatterAR() {


Loading…
Cancel
Save