Improve performance of AsYouTypeFormatter by precompliling regular expressions and...
authorjia.shao.peng <jia.shao.peng@ee073f10-1060-11df-b6a4-87a95322a99c>
Thu, 20 May 2010 00:54:27 +0000 (00:54 +0000)
committerjia.shao.peng <jia.shao.peng@ee073f10-1060-11df-b6a4-87a95322a99c>
Thu, 20 May 2010 00:54:27 +0000 (00:54 +0000)
git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@19 ee073f10-1060-11df-b6a4-87a95322a99c

java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java

index 37e4262..c5999bf 100644 (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;
   }
index 01e14d8..cefb3ec 100644 (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() {