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 StringBuffer prefixBeforeNationalNumber;
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
@ -125,17 +127,16 @@ public class AsYouTypeFormatter {
String numberPattern = format.getPattern();
// 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;
}
// 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
numberPattern = numberPattern.replaceAll("\\d(?=[^,}])", "\\\\d");
numberPattern = STANDALONE_DIGIT_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
formattingTemplate = getFormattingTemplate(numberPattern, numberFormat);
return true;
@ -161,12 +162,12 @@ public class AsYouTypeFormatter {
* Clears the internal state of the formatter, so it could be reused.
*/
public void clear() {
accruedInput = new StringBuffer();
accruedInputWithoutFormatting = new StringBuffer();
currentOutput = new StringBuffer();
accruedInput.setLength(0);
accruedInputWithoutFormatting.setLength(0);
currentOutput.setLength(0);
lastMatchPosition = 0;
prefixBeforeNationalNumber = new StringBuffer();
nationalNumber = new StringBuffer();
prefixBeforeNationalNumber.setLength(0);
nationalNumber.setLength(0);
ableToFormat = true;
isInternationalFormatting = false;
if (!currentMetaData.equals(defaultMetaData)) {
@ -185,7 +186,7 @@ public class AsYouTypeFormatter {
public String inputDigit(char nextChar) {
accruedInput.append(nextChar);
// * 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;
}
if (!ableToFormat) {
@ -269,7 +270,7 @@ public class AsYouTypeFormatter {
* It returns true for all other cases.
*/
private boolean extractIddAndValidCountryCode() {
nationalNumber = new StringBuffer();
nationalNumber.setLength(0);
Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
if (iddMatcher.lookingAt()) {
isInternationalFormatting = true;
@ -292,7 +293,8 @@ public class AsYouTypeFormatter {
prefixBeforeNationalNumber.append(countryCode).append(" ");
}
} else {
nationalNumber = new StringBuffer(accruedInputWithoutFormatting);
nationalNumber.setLength(0);
nationalNumber.append(accruedInputWithoutFormatting);
}
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 22", 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();
assertEquals("6", formatter.inputDigit('6'));
@ -191,7 +193,7 @@ public class AsYouTypeFormatterTest extends TestCase {
assertEquals("800 MY AP", formatter.inputDigit('P'));
assertEquals("800 MY APP", formatter.inputDigit('P'));
assertEquals("800 MY APPL", formatter.inputDigit('L'));
assertEquals("800 MY APPLE", formatter.inputDigit('E'));
assertEquals("800 MY APPLE", formatter.inputDigit('E'));
}
public void testAsYouTypeFormatterGBFixedLine() {
@ -260,7 +262,7 @@ public class AsYouTypeFormatterTest extends TestCase {
assertEquals("0301", formatter.inputDigit('1'));
assertEquals("03012", formatter.inputDigit('2'));
assertEquals("030 123", formatter.inputDigit('3'));
assertEquals("030 1234", formatter.inputDigit('4'));
assertEquals("030 1234", formatter.inputDigit('4'));
}
public void testAsYouTypeFormatterAR() {


Loading…
Cancel
Save