Browse Source

Checking in first version of java libphonenumber

pull/567/head
Shaopeng Jia 16 years ago
committed by Mihaela Rosca
commit
a7c6c36f84
18 changed files with 13046 additions and 0 deletions
  1. +78
    -0
      java/build.xml
  2. BIN
      java/lib/google-guava.jar
  3. BIN
      java/lib/junit-4.8.1.jar
  4. BIN
      java/lib/protobuf-java-2.3.0.jar
  5. +328
    -0
      java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
  6. +232
    -0
      java/src/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java
  7. +237
    -0
      java/src/com/google/i18n/phonenumbers/BuildMetadataProtoFromXml.java
  8. +61
    -0
      java/src/com/google/i18n/phonenumbers/NumberParseException.java
  9. +5281
    -0
      java/src/com/google/i18n/phonenumbers/PhoneNumberMetaData.xml
  10. +381
    -0
      java/src/com/google/i18n/phonenumbers/PhoneNumberMetaDataForTesting.xml
  11. BIN
      java/src/com/google/i18n/phonenumbers/PhoneNumberMetadataProto
  12. BIN
      java/src/com/google/i18n/phonenumbers/PhoneNumberMetadataProtoForTesting
  13. +1654
    -0
      java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
  14. +1449
    -0
      java/src/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java
  15. +2603
    -0
      java/src/com/google/i18n/phonenumbers/Phonemetadata.java
  16. +462
    -0
      java/src/com/google/i18n/phonenumbers/Phonenumber.java
  17. +209
    -0
      java/src/com/google/i18n/phonenumbers/phonemetadata.proto
  18. +71
    -0
      java/src/com/google/i18n/phonenumbers/phonenumber.proto

+ 78
- 0
java/build.xml View File

@ -0,0 +1,78 @@
<?xml version="1.0" ?>
<project name="libphonenumber" default="compile">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="lib.dir" value="lib"/>
<property name="report.dir" value="${build.dir}/junitreport"/>
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<path id="test.classpath">
<pathelement location="${classes.dir}"/>
<pathelement location="lib/junit/junit-4.8.1.jar"/>
<pathelement location="${jar.dir}/${ant.project.name}-test.jar"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="compile" description="Compile Java source.">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
</target>
<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar">
<fileset dir="${classes.dir}">
<include name="**/*.class"/>
<exclude name="**/*Test*"/>
</fileset>
<fileset dir="${src.dir}">
<include name="**/PhoneNumberMetadataProto"/>
</fileset>
</jar>
</target>
<target name="test-jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}-test.jar">
<fileset dir="${classes.dir}">
<include name="**/*.class"/>
<exclude name="**/*Test*"/>
</fileset>
<fileset dir="${src.dir}">
<include name="**/PhoneNumberMetadataProtoForTesting"/>
</fileset>
</jar>
</target>
<target name="junit" depends="test-jar">
<mkdir dir="${report.dir}"/>
<junit printsummary="yes">
<classpath refid="test.classpath"/>
<formatter type="xml"/>
<batchtest fork="no" todir="${report.dir}">
<fileset dir="${src.dir}" includes="**/*Test.java"/>
</batchtest>
</junit>
</target>
<target name="junitreport">
<junitreport todir="${report.dir}">
<fileset dir="${report.dir}" includes="TEST-*.xml"/>
<report todir="${report.dir}"/>
</junitreport>
</target>
<target name="clean" description="Remove generated files.">
<delete dir="${build.dir}"/>
</target>
<target name="clean-build" depends="clean,jar"/>
</project>

BIN
java/lib/google-guava.jar View File


BIN
java/lib/junit-4.8.1.jar View File


BIN
java/lib/protobuf-java-2.3.0.jar View File


+ 328
- 0
java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java View File

@ -0,0 +1,328 @@
/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.i18n.phonenumbers;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A formatter which formats phone numbers as they are entered.
*
* An AsYouTypeFormatter could be created by invoking the getAsYouTypeFormatter method of the
* PhoneNumberUtil. After that digits could be added by invoking the inputDigit method on the
* formatter instance, and the partially formatted phone number will be returned each time a digit
* is added. The clear method could be invoked before a new number needs to be formatted.
*
* See testAsYouTypeFormatterUS(), testAsYouTestFormatterGB() and testAsYouTypeFormatterDE() in
* PhoneNumberUtilTest.java for more details on how the formatter is to be used.
*
* @author Shaopeng Jia
*/
public class AsYouTypeFormatter {
private StringBuffer currentOutput;
private String formattingTemplate;
private StringBuffer accruedInput;
private StringBuffer accruedInputWithoutFormatting;
private boolean ableToFormat;
private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
private String defaultCountry;
private PhoneMetadata defaultMetaData;
private PhoneMetadata currentMetaData;
// The digits that have not been entered yet will be represented by a \u2008, the punctuation
// space.
private String digitPlaceholder = "\u2008";
private Pattern digitPattern = Pattern.compile(digitPlaceholder);
private int lastMatchPosition = 0;
private Pattern nationalPrefixForParsing;
private Pattern internationalPrefix;
private StringBuffer prefixBeforeNationalNumber;
private StringBuffer nationalNumber;
/**
* Constructs a light-weight formatter which does no formatting, but outputs exactly what is
* fed into the inputDigit method.
*
* @param regionCode the country/region where the phone number is being entered
*/
AsYouTypeFormatter(String regionCode) {
accruedInput = new StringBuffer();
accruedInputWithoutFormatting = new StringBuffer();
currentOutput = new StringBuffer();
prefixBeforeNationalNumber = new StringBuffer();
ableToFormat = true;
nationalNumber = new StringBuffer();
defaultCountry = regionCode;
initializeCountrySpecificInfo(defaultCountry);
defaultMetaData = currentMetaData;
}
private void initializeCountrySpecificInfo(String regionCode) {
currentMetaData = phoneUtil.getMetadataForRegion(regionCode);
nationalPrefixForParsing =
Pattern.compile(currentMetaData.getNationalPrefixForParsing());
internationalPrefix =
Pattern.compile("\\+|" + currentMetaData.getInternationalPrefix());
}
private void chooseFormatAndCreateTemplate(String leadingFourDigitsOfNationalNumber) {
List<NumberFormat> formatList = getAvailableFormats(leadingFourDigitsOfNationalNumber);
if (formatList.size() < 1) {
ableToFormat = false;
} else {
// When there are multiple available formats, the formatter uses the first format.
NumberFormat format = formatList.get(0);
if (!createFormattingTemplate(format)) {
ableToFormat = false;
} else {
currentOutput = new StringBuffer(formattingTemplate);
}
}
}
private List<NumberFormat> getAvailableFormats(String leadingFourDigits) {
List<NumberFormat> matchedList = new ArrayList<NumberFormat>();
List<NumberFormat> formatList = currentMetaData.getNumberFormatList();
for (NumberFormat format : formatList) {
if (format.hasLeadingDigits()) {
Pattern leadingDigitsPattern = Pattern.compile(format.getLeadingDigits());
Matcher m = leadingDigitsPattern.matcher(leadingFourDigits);
if (m.lookingAt()) {
matchedList.add(format);
}
} else {
matchedList.add(format);
}
}
return matchedList;
}
private boolean createFormattingTemplate(NumberFormat format) {
String numberFormat = format.getFormat();
String numberPattern = format.getPattern();
// The formatter doesn't format numbers when numberPattern contains "|" or ",", e.g.
// (20|3)\d{4,5}. In those cases we quickly return.
Matcher unsupportedSyntax = Pattern.compile("\\||,").matcher(numberPattern);
if (unsupportedSyntax.find()) {
return false;
}
// Replace anything in the form of [..] with \d
numberPattern = numberPattern.replaceAll("\\[([^\\[\\]])*\\]","\\\\d");
// Replace any standalone digit (not the one in d{}) with \d
numberPattern = numberPattern.replaceAll("\\d(?=[^}])", "\\\\d");
formattingTemplate = getFormattingTemplate(numberPattern, numberFormat);
return true;
}
// Gets a formatting template which could be used to efficiently format a partial number where
// digits are added one by one.
private String getFormattingTemplate(String numberPattern, String numberFormat) {
// Creates a phone number consisting only of the digit 9 that matches the
// numberPattern by applying the pattern to the longestPhoneNumber string.
String longestPhoneNumber = "999999999999999";
Matcher m = Pattern.compile(numberPattern).matcher(longestPhoneNumber);
m.find(); // this will always succeed
String aPhoneNumber = m.group();
// Formats the number according to numberFormat
String template = aPhoneNumber.replaceAll(numberPattern, numberFormat);
// Replaces each digit with character digitPlaceholder
template = template.replaceAll("9", digitPlaceholder);
return template;
}
/**
* Clears the internal state of the formatter, so it could be reused.
*/
public void clear() {
accruedInput = new StringBuffer();
accruedInputWithoutFormatting = new StringBuffer();
currentOutput = new StringBuffer();
lastMatchPosition = 0;
prefixBeforeNationalNumber = new StringBuffer();
nationalNumber = new StringBuffer();
ableToFormat = true;
if (!currentMetaData.equals(defaultMetaData)) {
initializeCountrySpecificInfo(defaultCountry);
}
}
/**
* Formats a phone number on-the-fly as each digit is entered.
*
* @param nextChar the most recently entered digit of a phone number. Formatting characters are
* allowed, but they are removed from the result. Full width digits and Arabic-indic digits
* are allowed, and will be shown as they are.
* @return the partially formatted phone number, with the remaining digits each denoted by
* \u2008. Clients could display the result as it is, as \u2008 will be displayed as a normal
* white space.
*/
public String inputDigit(char nextChar) {
accruedInput.append(nextChar);
// * and # are normally used in mobile codes, which we do not format.
if (nextChar == '*' || nextChar == '#') {
ableToFormat = false;
}
if (!ableToFormat) {
return accruedInput.toString();
}
nextChar = normalizeAndAccrueDigitsAndPlusSign(nextChar);
// We start to attempt to format only when at least 6 digits (the plus sign is counted as a
// digit as well for this purpose) have been entered.
switch (accruedInputWithoutFormatting.length()) {
case 0: // this is the case where the first few inputs are neither digits nor the plus sign.
case 1:
case 2:
case 3:
case 4:
case 5:
return accruedInput.toString();
case 6:
if (!extractIddAndValidCountryCode()) {
ableToFormat = false;
return accruedInput.toString();
}
removeNationalPrefixFromNationalNumber();
return attemptToChooseFormattingPattern();
default:
if (nationalNumber.length() > 4) { // The formatting pattern is already chosen.
return prefixBeforeNationalNumber + inputDigitHelper(nextChar);
} else {
return attemptToChooseFormattingPattern();
}
}
}
// Attempts to set the formatting template and returns a string which contains the formatted
// version of the digits entered so far.
private String attemptToChooseFormattingPattern() {
// We start to attempt to format only when as least 4 digits of national number (excluding
// national prefix) have been entered.
if (nationalNumber.length() >= 4) {
chooseFormatAndCreateTemplate(nationalNumber.substring(0, 4));
return inputAccruedNationalNumber();
} else {
return prefixBeforeNationalNumber + nationalNumber.toString();
}
}
// Invokes inputDigitHelper on each digit of the national number accrued, and returns a formatted
// string in the end.
private String inputAccruedNationalNumber() {
int lengthOfNationalNumber = nationalNumber.length();
if (lengthOfNationalNumber > 0) {
for (int i = 0; i < lengthOfNationalNumber - 1; i++) {
inputDigitHelper(nationalNumber.charAt(i));
}
return prefixBeforeNationalNumber
+ inputDigitHelper(nationalNumber.charAt(lengthOfNationalNumber - 1));
} else {
return prefixBeforeNationalNumber.toString();
}
}
private void removeNationalPrefixFromNationalNumber() {
int startOfNationalNumber = 0;
if (currentMetaData.hasNationalPrefix()) {
Matcher m = nationalPrefixForParsing.matcher(nationalNumber);
if (m.lookingAt()) {
startOfNationalNumber = m.end();
prefixBeforeNationalNumber.append(nationalNumber.substring(0, startOfNationalNumber));
}
}
nationalNumber.delete(0, startOfNationalNumber);
}
/**
* Extracts IDD, plus sign and country code to prefixBeforeNationalNumber when they are available,
* and places the remaining input into nationalNumber.
*
* @return false when accruedInputWithoutFormatting begins with the plus sign or valid IDD for
* defaultCountry, but the sequence of digits after that does not form a valid country code.
* It returns true for all other cases.
*/
private boolean extractIddAndValidCountryCode() {
nationalNumber = new StringBuffer();
Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
if (iddMatcher.lookingAt()) {
int startOfCountryCode = iddMatcher.end();
StringBuffer numberIncludeCountryCode =
new StringBuffer(accruedInputWithoutFormatting.substring(startOfCountryCode));
int countryCode = phoneUtil.extractCountryCode(numberIncludeCountryCode, nationalNumber);
if (countryCode == 0) {
return false;
} else {
String newRegionCode = phoneUtil.getRegionCodeForCountryCode(countryCode);
if (!newRegionCode.equals(defaultCountry)) {
initializeCountrySpecificInfo(newRegionCode);
}
prefixBeforeNationalNumber.append(
accruedInputWithoutFormatting.substring(0, startOfCountryCode));
if (accruedInputWithoutFormatting.charAt(0) != PhoneNumberUtil.PLUS_SIGN ) {
prefixBeforeNationalNumber.append(" ");
}
prefixBeforeNationalNumber.append(countryCode).append(" ");
}
} else {
nationalNumber = new StringBuffer(accruedInputWithoutFormatting);
}
return true;
}
// Accrues digits and the plus sign to accruedInputWithoutFormatting for later use. If nextChar
// contains a digit in non-ASCII format (e.g. the full-width version of digits), it is first
// normalized to the ASCII version. The return value is nextChar itself, or its normalized
// version, if nextChar is a digit in non-ASCII format.
private char normalizeAndAccrueDigitsAndPlusSign(char nextChar) {
if (nextChar == PhoneNumberUtil.PLUS_SIGN) {
accruedInputWithoutFormatting.append(nextChar);
}
if (PhoneNumberUtil.DIGIT_MAPPINGS.containsKey(nextChar)) {
nextChar = PhoneNumberUtil.DIGIT_MAPPINGS.get(nextChar);
accruedInputWithoutFormatting.append(nextChar);
nationalNumber.append(nextChar);
}
return nextChar;
}
private String inputDigitHelper(char nextChar) {
if (!PhoneNumberUtil.DIGIT_MAPPINGS.containsKey(nextChar)) {
return currentOutput.toString();
}
Matcher digitMatcher = digitPattern.matcher(currentOutput);
if (digitMatcher.find(lastMatchPosition)) {
currentOutput = new StringBuffer(digitMatcher.replaceFirst(Character.toString(nextChar)));
lastMatchPosition = digitMatcher.start();
} else { // More digits are entered than we could handle.
currentOutput.append(nextChar);
ableToFormat = false;
}
return currentOutput.toString();
}
}

+ 232
- 0
java/src/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java View File

@ -0,0 +1,232 @@
/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.i18n.phonenumbers;
import junit.framework.TestCase;
import java.io.InputStream;
/**
* Unit tests for PhoneNumberUtil.java
*
* Note that these tests use the metadata contained in the file specified by TEST_META_DATA_FILE,
* not the normal metadata file, so should not be used for regression test purposes - these tests
* are illustrative only and test functionality.
*
* @author Shaopeng Jia
*/
public class AsYouTypeFormatterTest extends TestCase {
private PhoneNumberUtil phoneUtil;
private static final String TEST_META_DATA_FILE =
"/com/google/i18n/phonenumbers/PhoneNumberMetadataProtoForTesting";
public AsYouTypeFormatterTest() {
PhoneNumberUtil.resetInstance();
InputStream in = PhoneNumberUtilTest.class.getResourceAsStream(TEST_META_DATA_FILE);
phoneUtil = PhoneNumberUtil.getInstance(in);
}
public void testAsYouTypeFormatterUS() {
AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("US");
assertEquals("6", formatter.inputDigit('6'));
assertEquals("65", formatter.inputDigit('5'));
assertEquals("650", formatter.inputDigit('0'));
assertEquals("6502", formatter.inputDigit('2'));
assertEquals("65025", formatter.inputDigit('5'));
assertEquals("650 253 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("650 253 2\u2008\u2008\u2008", formatter.inputDigit('2'));
assertEquals("650 253 22\u2008\u2008", formatter.inputDigit('2'));
assertEquals("650 253 222\u2008", formatter.inputDigit('2'));
assertEquals("650 253 2222", formatter.inputDigit('2'));
formatter.clear();
assertEquals("6", formatter.inputDigit('6'));
assertEquals("65", formatter.inputDigit('5'));
assertEquals("650", formatter.inputDigit('0'));
assertEquals("6502", formatter.inputDigit('2'));
assertEquals("65025", formatter.inputDigit('5'));
assertEquals("650 253 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("650 253 2\u2008\u2008\u2008", formatter.inputDigit('2'));
assertEquals("650 253 22\u2008\u2008", formatter.inputDigit('2'));
assertEquals("650 253 222\u2008", formatter.inputDigit('2'));
assertEquals("650 253 2222", formatter.inputDigit('2'));
formatter.clear();
assertEquals("6", formatter.inputDigit('6'));
assertEquals("65", formatter.inputDigit('5'));
assertEquals("650", formatter.inputDigit('0'));
assertEquals("650-", formatter.inputDigit('-'));
assertEquals("650-2", formatter.inputDigit('2'));
assertEquals("650-25", formatter.inputDigit('5'));
assertEquals("650 253 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("650 253 \u2008\u2008\u2008\u2008", formatter.inputDigit('-'));
assertEquals("650 253 2\u2008\u2008\u2008", formatter.inputDigit('2'));
assertEquals("650 253 22\u2008\u2008", formatter.inputDigit('2'));
assertEquals("650 253 222\u2008", formatter.inputDigit('2'));
assertEquals("650 253 2222", formatter.inputDigit('2'));
formatter.clear();
assertEquals("0", formatter.inputDigit('0'));
assertEquals("01", formatter.inputDigit('1'));
assertEquals("011", formatter.inputDigit('1'));
assertEquals("0114", formatter.inputDigit('4'));
assertEquals("01148", formatter.inputDigit('8'));
assertEquals("011 48 8", formatter.inputDigit('8'));
assertEquals("011 48 88", formatter.inputDigit('8'));
assertEquals("011 48 881", formatter.inputDigit('1'));
assertEquals("011 48 88 12\u2008 \u2008\u2008 \u2008\u2008", formatter.inputDigit('2'));
assertEquals("011 48 88 123 \u2008\u2008 \u2008\u2008", formatter.inputDigit('3'));
assertEquals("011 48 88 123 1\u2008 \u2008\u2008", formatter.inputDigit('1'));
assertEquals("011 48 88 123 12 \u2008\u2008", formatter.inputDigit('2'));
assertEquals("011 48 88 123 12 1\u2008", formatter.inputDigit('1'));
assertEquals("011 48 88 123 12 12", formatter.inputDigit('2'));
formatter.clear();
assertEquals("0", formatter.inputDigit('0'));
assertEquals("01", formatter.inputDigit('1'));
assertEquals("011", formatter.inputDigit('1'));
assertEquals("0114", formatter.inputDigit('4'));
assertEquals("01144", formatter.inputDigit('4'));
assertEquals("011 44 6", formatter.inputDigit('6'));
assertEquals("011 44 61", formatter.inputDigit('1'));
assertEquals("011 44 612", formatter.inputDigit('2'));
assertEquals("011 44 6 123 \u2008\u2008\u2008 \u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("011 44 6 123 1\u2008\u2008 \u2008\u2008\u2008", formatter.inputDigit('1'));
assertEquals("011 44 6 123 12\u2008 \u2008\u2008\u2008", formatter.inputDigit('2'));
assertEquals("011 44 6 123 123 \u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("011 44 6 123 123 1\u2008\u2008", formatter.inputDigit('1'));
assertEquals("011 44 6 123 123 12\u2008", formatter.inputDigit('2'));
assertEquals("011 44 6 123 123 123", formatter.inputDigit('3'));
formatter.clear();
assertEquals("+", formatter.inputDigit('+'));
assertEquals("+1", formatter.inputDigit('1'));
assertEquals("+16", formatter.inputDigit('6'));
assertEquals("+165", formatter.inputDigit('5'));
assertEquals("+1650", formatter.inputDigit('0'));
assertEquals("+1 650 2\u2008\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('2'));
assertEquals("+1 650 25\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('5'));
assertEquals("+1 650 253 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("+1 650 253 2\u2008\u2008\u2008", formatter.inputDigit('2'));
assertEquals("+1 650 253 22\u2008\u2008", formatter.inputDigit('2'));
assertEquals("+1 650 253 222\u2008", formatter.inputDigit('2'));
formatter.clear();
assertEquals("+", formatter.inputDigit('+'));
assertEquals("+4", formatter.inputDigit('4'));
assertEquals("+48", formatter.inputDigit('8'));
assertEquals("+488", formatter.inputDigit('8'));
assertEquals("+4888", formatter.inputDigit('8'));
assertEquals("+48 881", formatter.inputDigit('1'));
assertEquals("+48 88 12\u2008 \u2008\u2008 \u2008\u2008", formatter.inputDigit('2'));
assertEquals("+48 88 123 \u2008\u2008 \u2008\u2008", formatter.inputDigit('3'));
assertEquals("+48 88 123 1\u2008 \u2008\u2008", formatter.inputDigit('1'));
assertEquals("+48 88 123 12 \u2008\u2008", formatter.inputDigit('2'));
assertEquals("+48 88 123 12 1\u2008", formatter.inputDigit('1'));
assertEquals("+48 88 123 12 12", formatter.inputDigit('2'));
// Test US number with full-width characters.
formatter.clear();
assertEquals("\uFF16", formatter.inputDigit('\uFF16'));
assertEquals("\uFF16\uFF15", formatter.inputDigit('\uFF15'));
assertEquals("\uFF16\uFF15\uFF10", formatter.inputDigit('\uFF10'));
assertEquals("\uFF16\uFF15\uFF10\uFF12", formatter.inputDigit('\uFF12'));
assertEquals("\uFF16\uFF15\uFF10\uFF12\uFF15", formatter.inputDigit('\uFF15'));
assertEquals("650 253 \u2008\u2008\u2008\u2008", formatter.inputDigit('\uFF13'));
assertEquals("650 253 2\u2008\u2008\u2008", formatter.inputDigit('\uFF12'));
assertEquals("650 253 22\u2008\u2008", formatter.inputDigit('\uFF12'));
assertEquals("650 253 222\u2008", formatter.inputDigit('\uFF12'));
assertEquals("650 253 2222", formatter.inputDigit('\uFF12'));
// Mobile short code.
formatter.clear();
assertEquals("*", formatter.inputDigit('*'));
assertEquals("*1", formatter.inputDigit('1'));
assertEquals("*12", formatter.inputDigit('2'));
assertEquals("*121", formatter.inputDigit('1'));
assertEquals("*121#", formatter.inputDigit('#'));
}
public void testAsYouTypeFormatterGBFixedLine() {
AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("GB");
assertEquals("0", formatter.inputDigit('0'));
assertEquals("02", formatter.inputDigit('2'));
assertEquals("020", formatter.inputDigit('0'));
assertEquals("0207", formatter.inputDigit('7'));
assertEquals("02070", formatter.inputDigit('0'));
assertEquals("020 703\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("020 7031 \u2008\u2008\u2008\u2008", formatter.inputDigit('1'));
assertEquals("020 7031 3\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("020 7031 30\u2008\u2008", formatter.inputDigit('0'));
assertEquals("020 7031 300\u2008", formatter.inputDigit('0'));
assertEquals("020 7031 3000", formatter.inputDigit('0'));
}
public void testAsYouTypeFormatterGBTollFree() {
AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("GB");
assertEquals("0", formatter.inputDigit('0'));
assertEquals("08", formatter.inputDigit('8'));
assertEquals("080", formatter.inputDigit('0'));
assertEquals("0807", formatter.inputDigit('7'));
assertEquals("08070", formatter.inputDigit('0'));
assertEquals("080 703\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("080 7031 \u2008\u2008\u2008\u2008", formatter.inputDigit('1'));
assertEquals("080 7031 3\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("080 7031 30\u2008\u2008", formatter.inputDigit('0'));
assertEquals("080 7031 300\u2008", formatter.inputDigit('0'));
assertEquals("080 7031 3000", formatter.inputDigit('0'));
}
public void testAsYouTypeFormatterGBPremiumRate() {
AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("GB");
assertEquals("0", formatter.inputDigit('0'));
assertEquals("09", formatter.inputDigit('9'));
assertEquals("090", formatter.inputDigit('0'));
assertEquals("0907", formatter.inputDigit('7'));
assertEquals("09070", formatter.inputDigit('0'));
assertEquals("090 703\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("090 7031 \u2008\u2008\u2008\u2008", formatter.inputDigit('1'));
assertEquals("090 7031 3\u2008\u2008\u2008", formatter.inputDigit('3'));
assertEquals("090 7031 30\u2008\u2008", formatter.inputDigit('0'));
assertEquals("090 7031 300\u2008", formatter.inputDigit('0'));
assertEquals("090 7031 3000", formatter.inputDigit('0'));
}
public void testAsYouTypeFormatterNZMobile() {
AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("NZ");
assertEquals("0", formatter.inputDigit('0'));
assertEquals("02", formatter.inputDigit('2'));
assertEquals("021", formatter.inputDigit('1'));
assertEquals("0211", formatter.inputDigit('1'));
assertEquals("02112", formatter.inputDigit('2'));
assertEquals("021123", formatter.inputDigit('3'));
assertEquals("0211234", formatter.inputDigit('4'));
assertEquals("02112345", formatter.inputDigit('5'));
assertEquals("021123456", formatter.inputDigit('6'));
}
public void testAsYouTypeFormatterDE() {
AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("DE");
assertEquals("0", formatter.inputDigit('0'));
assertEquals("03", formatter.inputDigit('3'));
assertEquals("030", formatter.inputDigit('0'));
assertEquals("0301", formatter.inputDigit('1'));
assertEquals("03012", formatter.inputDigit('2'));
assertEquals("030123", formatter.inputDigit('3'));
assertEquals("0301234", formatter.inputDigit('4'));
}
}

+ 237
- 0
java/src/com/google/i18n/phonenumbers/BuildMetadataProtoFromXml.java View File

@ -0,0 +1,237 @@
/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.i18n.phonenumbers;
import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
/**
* Tool to convert phone number metadata from the XML format to protocol buffer format. It is
* wrapped in the genrule of the BUILD file and run as a preprocessing step when building the
* phone number library. Example command line invocation:
*
* ./BuildMetadataProtoFromXml PhoneNumberMetadata.xml PhoneNumberMetadataProto true
*
* When liteBuild flag is set to true, the outputFile generated omits certain metadata which is not
* needed for clients using liteBuild. At this moment, example numbers information is omitted.
*
* @author Shaopeng Jia
*/
public class BuildMetadataProtoFromXml {
private BuildMetadataProtoFromXml() {
}
private static final Logger LOGGER = Logger.getLogger(BuildMetadataProtoFromXml.class.getName());
private static Boolean liteBuild;
public static void main(String[] args) {
String inputFile = args[0];
String outputFile = args[1];
liteBuild = args.length > 2 && Boolean.getBoolean(args[2]);
File xmlFile = new File(inputFile);
try {
FileOutputStream output = new FileOutputStream(outputFile);
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse(xmlFile);
document.getDocumentElement().normalize();
Element rootElement = document.getDocumentElement();
NodeList territory = rootElement.getElementsByTagName("territory");
PhoneMetadataCollection.Builder metadataCollection = PhoneMetadataCollection.newBuilder();
int numOfTerritories = territory.getLength();
for (int i = 0; i < numOfTerritories; i++) {
Element territoryElement = (Element) territory.item(i);
String regionCode = territoryElement.getAttribute("id");
PhoneMetadata metadata = loadCountryMetadata(regionCode, territoryElement);
metadataCollection.addMetadata(metadata);
}
metadataCollection.build().writeTo(output);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.toString());
} catch (SAXException e) {
LOGGER.log(Level.SEVERE, e.toString());
} catch (ParserConfigurationException e) {
LOGGER.log(Level.SEVERE, e.toString());
}
}
private static PhoneMetadata loadCountryMetadata(String regionCode, Element element) {
PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder();
metadata.setId(regionCode);
metadata.setCountryCode(Integer.parseInt(element.getAttribute("countryCode")));
metadata.setInternationalPrefix(element.getAttribute("internationalPrefix"));
if (element.hasAttribute("preferredInternationalPrefix")) {
String preferredInternationalPrefix = element.getAttribute("preferredInternationalPrefix");
metadata.setPreferredInternationalPrefix(preferredInternationalPrefix);
}
String nationalPrefix = "";
if (element.hasAttribute("nationalPrefix")) {
nationalPrefix = element.getAttribute("nationalPrefix");
metadata.setNationalPrefix(nationalPrefix);
metadata.setNationalPrefixFormattingRule(
getNationalPrefixFormattingRuleFromElement(element, nationalPrefix));
if (element.hasAttribute("nationalPrefixForParsing")) {
metadata.setNationalPrefixForParsing(element.getAttribute("nationalPrefixForParsing"));
if (element.hasAttribute("nationalPrefixTransformRule")) {
metadata.setNationalPrefixTransformRule(
element.getAttribute("nationalPrefixTransformRule"));
}
} else {
metadata.setNationalPrefixForParsing(nationalPrefix);
}
}
if (element.hasAttribute("preferredExtnPrefix")) {
metadata.setPreferredExtnPrefix(element.getAttribute("preferredExtnPrefix"));
}
// Extract availableFormats
NodeList numberFormatElements = element.getElementsByTagName("numberFormat");
int numOfFormatElements = numberFormatElements.getLength();
if (numOfFormatElements > 0) {
for (int i = 0; i < numOfFormatElements; i++) {
Element numberFormatElement = (Element) numberFormatElements.item(i);
NumberFormat.Builder format = NumberFormat.newBuilder();
if (numberFormatElement.hasAttribute("nationalPrefixFormattingRule")) {
format.setNationalPrefixFormattingRule(
getNationalPrefixFormattingRuleFromElement(numberFormatElement, nationalPrefix));
} else {
format.setNationalPrefixFormattingRule(metadata.getNationalPrefixFormattingRule());
}
if (numberFormatElement.hasAttribute("leadingDigits")) {
format.setLeadingDigits(numberFormatElement.getAttribute("leadingDigits"));
}
format.setPattern(numberFormatElement.getAttribute("pattern"));
String formatValue = numberFormatElement.getFirstChild().getNodeValue();
format.setFormat(formatValue);
metadata.addNumberFormat(format.build());
}
}
NodeList intlNumberFormatElements = element.getElementsByTagName("intlNumberFormat");
int numOfIntlFormatElements = intlNumberFormatElements.getLength();
if (numOfIntlFormatElements > 0) {
for (int i = 0; i < numOfIntlFormatElements; i++) {
Element numberFormatElement = (Element) intlNumberFormatElements.item(i);
NumberFormat.Builder format = NumberFormat.newBuilder();
if (numberFormatElement.hasAttribute("leadingDigits")) {
format.setLeadingDigits(numberFormatElement.getAttribute("leadingDigits"));
}
format.setPattern(numberFormatElement.getAttribute("pattern"));
format.setFormat(numberFormatElement.getFirstChild().getNodeValue());
metadata.addIntlNumberFormat(format.build());
}
}
PhoneNumberDesc generalDesc =
processPhoneNumberDescElement(PhoneNumberDesc.newBuilder().build(),
element, "generalDesc");
metadata.setGeneralDesc(generalDesc);
metadata.setFixedLine(processPhoneNumberDescElement(generalDesc, element, "fixedLine"));
metadata.setMobile(processPhoneNumberDescElement(generalDesc, element, "mobile"));
metadata.setTollFree(processPhoneNumberDescElement(generalDesc, element, "tollFree"));
metadata.setPremiumRate(processPhoneNumberDescElement(generalDesc, element, "premiumRate"));
metadata.setSharedCost(processPhoneNumberDescElement(generalDesc, element, "sharedCost"));
metadata.setVoip(processPhoneNumberDescElement(generalDesc, element, "voip"));
metadata.setPersonalNumber(processPhoneNumberDescElement(generalDesc, element,
"personalNumber"));
if (metadata.getMobile().getNationalNumberPattern().equals(
metadata.getFixedLine().getNationalNumberPattern())) {
metadata.setSameMobileAndFixedLinePattern(true);
}
return metadata.build();
}
private static String getNationalPrefixFormattingRuleFromElement(Element element,
String nationalPrefix) {
String nationalPrefixFormattingRule = element.getAttribute("nationalPrefixFormattingRule");
// Replace $NP with national prefix and $FG with the first group ($1).
nationalPrefixFormattingRule =
nationalPrefixFormattingRule.replaceFirst("\\$NP", nationalPrefix)
.replaceFirst("\\$FG", "\\$1");
return nationalPrefixFormattingRule;
}
/**
* Processes a phone number description element from the XML file and returns it as a
* PhoneNumberDesc. If the description element is a fixed line or mobile number, the general
* description will be used to fill in the whole element if necessary, or any components that are
* missing. For all other types, the general description will only be used to fill in missing
* components if the type has a partial definition. For example, if no "tollFree" element exists,
* we assume there are no toll free numbers for that locale, and return a phone number description
* with "NA" for both the national and possible number patterns.
*
* @param generalDesc a generic phone number description that will be used to fill in missing
* parts of the description
* @param countryElement the XML element representing all the country information
* @param numberType the name of the number type, corresponding to the appropriate tag in the XML
* file with information about that type
* @return complete description of that phone number type
*/
private static PhoneNumberDesc processPhoneNumberDescElement(PhoneNumberDesc generalDesc,
Element countryElement,
String numberType) {
NodeList phoneNumberDescList = countryElement.getElementsByTagName(numberType);
PhoneNumberDesc.Builder numberDesc = PhoneNumberDesc.newBuilder();
if (phoneNumberDescList.getLength() == 0 &&
(!numberType.equals("fixedLine") && !numberType.equals("mobile") &&
!numberType.equals("generalDesc"))) {
numberDesc.setNationalNumberPattern("NA");
numberDesc.setPossibleNumberPattern("NA");
return numberDesc.build();
}
numberDesc.mergeFrom(generalDesc);
if (phoneNumberDescList.getLength() > 0) {
Element element = (Element) phoneNumberDescList.item(0);
NodeList possiblePattern = element.getElementsByTagName("possibleNumberPattern");
if (possiblePattern.getLength() > 0) {
numberDesc.setPossibleNumberPattern(possiblePattern.
item(0).getFirstChild().getNodeValue());
}
NodeList validPattern = element.getElementsByTagName("nationalNumberPattern");
if (validPattern.getLength() > 0) {
numberDesc.setNationalNumberPattern(validPattern.
item(0).getFirstChild().getNodeValue());
}
if (!liteBuild) {
NodeList exampleNumber = element.getElementsByTagName("exampleNumber");
if (exampleNumber.getLength() > 0) {
numberDesc.setExampleNumber(exampleNumber.item(0).getFirstChild().getNodeValue());
}
}
}
return numberDesc.build();
}
}

+ 61
- 0
java/src/com/google/i18n/phonenumbers/NumberParseException.java View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.i18n.phonenumbers;
/**
* Generic exception class for errors encountered when parsing phone numbers.
* @author Lara Rennie
*/
public class NumberParseException extends Exception {
public enum ErrorType {
INVALID_COUNTRY_CODE,
// This generally indicates the string passed in had less than 3 digits in it. More
// specifically, the number failed to match the regular expression VALID_PHONE_NUMBER in
// PhoneNumberUtil.java.
NOT_A_NUMBER,
// This indicates the string started with an international dialing prefix, but after this was
// stripped from the number, had less digits than any valid phone number (including country
// code) could have.
TOO_SHORT_AFTER_IDD,
// This indicates the string, after any country code has been stripped, had less digits than any
// valid phone number could have.
TOO_SHORT_NSN,
// This indicates the string had more digits than any valid phone number could have.
TOO_LONG,
};
private ErrorType errorType;
private String message;
public NumberParseException(ErrorType errorType, String message) {
super(message);
this.message = message;
this.errorType = errorType;
}
/**
* Returns the error type of the exception that has been thrown.
*/
public ErrorType getErrorType() {
return errorType;
}
public String toString() {
return "Error type: " + errorType + ". " + message;
}
}

+ 5281
- 0
java/src/com/google/i18n/phonenumbers/PhoneNumberMetaData.xml
File diff suppressed because it is too large
View File


+ 381
- 0
java/src/com/google/i18n/phonenumbers/PhoneNumberMetaDataForTesting.xml View File

@ -0,0 +1,381 @@
<!-- Copyright (C) 2009 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@author: Shaopeng Jia
MetaData on Phone Number Plan and formatting rules. This file is used
solely for the purpose of unittesting, so data in this file is not
necessarily consistent with that of PhoneNumberMetaData.xml
-->
<phoneNumberMetadata>
<territories>
<!-- Andorra -->
<territory id="AD" countryCode="376" internationalPrefix="00">
</territory>
<!-- Argentina -->
<territory id="AR" countryCode="54" internationalPrefix="00"
nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG"
nationalPrefixForParsing="0(?:(11|343|3715)15)?"
nationalPrefixTransformRule="9$1">
<!-- Note in nationalPrefixForParsing, the areacode (such as 11, 343, etc.), when present in
front of carrier selection code 15, is captured to replace $1 in
nationalPrefixTransformRule -->
<availableFormats>
<numberFormat leadingDigits="11" pattern="(\d{2})(\d{4})(\d{4})">$1 $2-$3</numberFormat>
<numberFormat leadingDigits="1[02-9]|[23]" pattern="(\d{4})(\d{2})(\d{4})">$1 $2-$3</numberFormat>
<numberFormat leadingDigits="911" pattern="9(11)(\d{4})(\d{4})">$1 15 $2-$3</numberFormat>
<numberFormat leadingDigits="9(?:1[02-9]|[23])" pattern="9(\d{4})(\d{2})(\d{4})">$1 15 $2-$3</numberFormat>
<numberFormat leadingDigits="[68]" pattern="(\d{3})(\d{3})(\d{4})">$1-$2-$3</numberFormat>
<intlNumberFormat leadingDigits="11" pattern="(\d{2})(\d{4})(\d{4})">$1 $2-$3</intlNumberFormat>
<intlNumberFormat leadingDigits="1[02-9]|[23]" pattern="(\d{4})(\d{2})(\d{4})">$1 $2-$3</intlNumberFormat>
<intlNumberFormat leadingDigits="911" pattern="(9)(11)(\d{4})(\d{4})">$1 $2 $3 $4</intlNumberFormat>
<intlNumberFormat leadingDigits="9(?:1[02-9]|[23])" pattern="(9)(\d{4})(\d{2})(\d{4})">$1 $2 $3 $4</intlNumberFormat>
<intlNumberFormat leadingDigits="[68]" pattern="(\d{3})(\d{3})(\d{4})">$1-$2-$3</intlNumberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>[1-3689]\d{9,10}</nationalNumberPattern>
<possibleNumberPattern>\d{6,11}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>[1-3]\d{9}</nationalNumberPattern>
<possibleNumberPattern>\d{6,10}</possibleNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>9\d{10}|[1-3]\d{9}</nationalNumberPattern>
<possibleNumberPattern>\d{10,11}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>80\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>6(0\d|10)\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- Australia -->
<territory id="AU" countryCode="61" internationalPrefix="001[12]"
nationalPrefix="0" preferredInternationalPrefix="0011"
nationalPrefixFormattingRule="$NP$FG">
<availableFormats>
<numberFormat nationalPrefixFormattingRule="$FG" leadingDigits="1" pattern="(\d{4})(\d{3})(\d{3})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="[2-478]" pattern="(\d{1})(\d{4})(\d{4})">$1 $2 $3</numberFormat>
</availableFormats>
<generalDesc >
<nationalNumberPattern>[1-578]\d{4,14}</nationalNumberPattern>
<possibleNumberPattern>\d{5,15}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>[2378]\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{9}</possibleNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>4\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{9}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>1800\d{6}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>190[0126]\d{6}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- Bahamas -->
<territory id="BS" countryCode="1" internationalPrefix="011">
<availableFormats>
<numberFormat pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>(242|8(00|66|77|88)|900)\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{7,10}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>242(?:3(?:02|[236][1-9]|4[0-24-9]|5[0-68]|7[3-57]|9[2-5])|4(?:2[237]|51|64|77)|502|636|702)\d{4}</nationalNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>242(357|359|457|557)\d{4}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>8(00|66|77|88)\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>900\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- Germany -->
<territory id="DE" countryCode="49" internationalPrefix="00"
nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
<availableFormats>
<numberFormat leadingDigits="2|3[3-9]|906|[4-9][1-9]1" pattern="(\d{3})(\d{3,8})">$1 $2</numberFormat>
<numberFormat leadingDigits="[34]0|[68]9" pattern="(\d{2})(\d{4,9})">$1 $2</numberFormat>
<numberFormat leadingDigits="[4-9]" pattern="([4-9]\d{3})(\d{2,7})">$1 $2</numberFormat>
<numberFormat leadingDigits="800" pattern="(\d{3})(\d{1})(\d{6})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="900[135]" pattern="(\d{3})(\d{3})(d{4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="9009" pattern="(\d{3})(\d{4})(\d{4})">$1 $2 $3</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>\d{4,14}</nationalNumberPattern>
<possibleNumberPattern>\d{2,14}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>(?:[24-6]\d{2}|3[03-9]\d|[789](?:[1-9]\d|0[2-9]))\d{3,8}</nationalNumberPattern>
<exampleNumber>30123456</exampleNumber>
</fixedLine>
<mobile>
<nationalNumberPattern>1(5\d{9}|7\d{8}|6[02]\d{8}|63\d{7})</nationalNumberPattern>
<possibleNumberPattern>\d{10,11}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>800\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>900([135]\d{6}|9\d{7})</nationalNumberPattern>
<possibleNumberPattern>\d{10,11}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- United Kingdom -->
<territory id="GB" countryCode="44" internationalPrefix="00"
nationalPrefix="0" nationalPrefixFormattingRule="($NP$FG)">
<availableFormats>
<numberFormat leadingDigits="[1-59]|[78]0"
pattern="(\d{2})(\d{4})(\d{4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="6"
pattern="(\d)(\d{3})(\d{3})(\d{3})">$1 $2 $3 $4</numberFormat>
<numberFormat leadingDigits="7[1-57-9]"
pattern="(\d{4})(\d{3})(\d{3})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="8[47]"
pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>\d{10}</nationalNumberPattern>
<possibleNumberPattern>\d{6,10}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>[1-6]\d{9}</nationalNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>7[1-57-9]\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>80\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>9[018]\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</premiumRate>
<sharedCost>
<nationalNumberPattern>8(?:4[3-5]|7[0-2])\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</sharedCost>
<voip>
<nationalNumberPattern>56\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</voip>
<personalNumber>
<nationalNumberPattern>70\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</personalNumber>
</territory>
<!-- Italy -->
<!-- http://en.wikipedia.org/wiki/%2B39 -->
<territory id="IT" countryCode="39" internationalPrefix="00">
<availableFormats>
<numberFormat leadingDigits="0[26]" pattern="(\d{2})(\d{4})(\d{4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="0[13-57-9]" pattern="(\d{3})(\d{4})(\d{3,4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="3" pattern="(\d{3})(\d{3})(\d{3,4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="8" pattern="(\d{3})(\d{3,6})">$1 $2</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>[0389]\d{5,10}</nationalNumberPattern>
<possibleNumberPattern>\d{6,11}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>0\d{9,10}</nationalNumberPattern>
<possibleNumberPattern>\d{10,11}</possibleNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>3\d{8,9}</nationalNumberPattern>
<possibleNumberPattern>\d{9,10}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>80(?:0\d{6}|3\d{3})</nationalNumberPattern>
<possibleNumberPattern>\d{6,9}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>89(?:2\d{3}|9\d{6})</nationalNumberPattern>
<possibleNumberPattern>\d{6,9}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- Mexico -->
<territory id="MX" countryCode="52" internationalPrefix="00"
nationalPrefix="01" nationalPrefixForParsing="01|04[45](\d{10})"
nationalPrefixTransformRule="1$1">
<availableFormats>
<numberFormat leadingDigits="[89]00" pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="33|55|81" pattern="(\d{2})(\d{4})(\d{4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]" pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="1(?:33|55|81)" pattern="1(\d{2})(\d{4})(\d{4})">045 $1 $2 $3</numberFormat>
<numberFormat leadingDigits="1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])" pattern="1(\d{3})(\d{3})(\d{4})">045 $1 $2 $3</numberFormat>
<intlNumberFormat leadingDigits="[89]00" pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</intlNumberFormat>
<intlNumberFormat leadingDigits="33|55|81" pattern="(\d{2})(\d{4})(\d{4})">$1 $2 $3</intlNumberFormat>
<intlNumberFormat leadingDigits="[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]" pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</intlNumberFormat>
<intlNumberFormat leadingDigits="1(?:33|55|81)" pattern="(1)(\d{2})(\d{4})(\d{4})">$1 $2 $3 $4</intlNumberFormat>
<intlNumberFormat leadingDigits="1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])" pattern="(1)(\d{3})(\d{3})(\d{4})">$1 $2 $3 $4</intlNumberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>[1-9]\d{9,10}</nationalNumberPattern>
<possibleNumberPattern>\d{7,11}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>[2-9]\d{9}</nationalNumberPattern>
<possibleNumberPattern>\d{7,10}</possibleNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>1\d{10}</nationalNumberPattern>
<possibleNumberPattern>\d{11}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>800\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>900\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- New Zealand -->
<territory id="NZ" countryCode="64" internationalPrefix="00"
nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
<availableFormats>
<numberFormat leadingDigits="24|[34679]" pattern="(\d)(\d{3})(\d{4})">$1-$2 $3</numberFormat>
<numberFormat leadingDigits="2[179]" pattern="(\d)(\d{3})(\d{3,5})">$1-$2 $3</numberFormat>
<numberFormat leadingDigits="[89]" pattern="(\d{3})(\d{3})(\d{3,4})">$1 $2 $3</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>[2-9]\d{7,9}</nationalNumberPattern>
<possibleNumberPattern>\d{7,10}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>24099\d{3}|(?:3[2-79]|[479][2-689]|6[235-9])\d{6}</nationalNumberPattern>
<possibleNumberPattern>\d{7,8}</possibleNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>2(?:[027]\d{7}|9\d{6,7}|1(?:0\d{5,7}|[12]\d{5,6}|[3-9]\d{5})|4[1-9]\d{6}|8\d{7,8})</nationalNumberPattern>
<possibleNumberPattern>\d{8,10}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>800\d{6,7}</nationalNumberPattern>
<possibleNumberPattern>\d{9,10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>900\d{6,7}</nationalNumberPattern>
<possibleNumberPattern>\d{9,10}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- Poland -->
<!-- http://en.wikipedia.org/wiki/%2B48 -->
<territory id="PL" countryCode="48" internationalPrefix="0~0"
nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
<availableFormats>
<numberFormat pattern="(\d{2})(\d{3})(\d{2})(\d{2})">$1 $2 $3 $4</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>[1-9]\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{9}</possibleNumberPattern>
</generalDesc>
<mobile>
<nationalNumberPattern>(?:5[01]|6[069]|7[289]|88)\d{7}</nationalNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>800\d{6}</nationalNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>70\d{7}</nationalNumberPattern>
</premiumRate>
</territory>
<!-- Singapore -->
<!-- http://www.ida.gov.sg/policies%20and%20regulation/20060508120124.aspx -->
<territory id="SG" countryCode="65" internationalPrefix="0[0-3][0-9]">
<availableFormats>
<numberFormat leadingDigits="[369]|8[1-9]" pattern="(\d{4})(\d{4})">$1 $2</numberFormat>
<numberFormat leadingDigits="1[89]" pattern="(\d{4})(\d{3})(\d{4})">$1 $2 $3</numberFormat>
<numberFormat leadingDigits="800" pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>[13689]\d{7,10}</nationalNumberPattern>
<possibleNumberPattern>\d{8,11}</possibleNumberPattern>
</generalDesc>
<fixedLine>
<nationalNumberPattern>[36]\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{8}</possibleNumberPattern>
</fixedLine>
<mobile>
<nationalNumberPattern>[89]\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{8}</possibleNumberPattern>
</mobile>
<tollFree>
<nationalNumberPattern>1?800\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10,11}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>1900\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{11}</possibleNumberPattern>
</premiumRate>
</territory>
<!-- United States -->
<!-- http://www.nanpa.com/reports/reports_npa.html -->
<!-- For testing purposes, numbers starting with 24 are not considered US
numbers.-->
<territory id="US" countryCode="1" internationalPrefix="011"
preferredExtnPrefix=" extn. ">
<availableFormats>
<numberFormat pattern="(\d{3})(\d{3})(\d{4})">$1 $2 $3</numberFormat>
<numberFormat pattern="(\d{3})(\d{4})">$1 $2</numberFormat>
</availableFormats>
<generalDesc>
<nationalNumberPattern>[13-9]\d{9}|2[0-35-9]\d{8}</nationalNumberPattern>
<possibleNumberPattern>\d{7,10}</possibleNumberPattern>
<exampleNumber>1234567890</exampleNumber>
</generalDesc>
<tollFree>
<nationalNumberPattern>8(00|66|77|88)\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</tollFree>
<premiumRate>
<nationalNumberPattern>900\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{10}</possibleNumberPattern>
</premiumRate>
</territory>
</territories>
</phoneNumberMetadata>

BIN
java/src/com/google/i18n/phonenumbers/PhoneNumberMetadataProto View File


BIN
java/src/com/google/i18n/phonenumbers/PhoneNumberMetadataProtoForTesting View File


+ 1654
- 0
java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
File diff suppressed because it is too large
View File


+ 1449
- 0
java/src/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java
File diff suppressed because it is too large
View File


+ 2603
- 0
java/src/com/google/i18n/phonenumbers/Phonemetadata.java
File diff suppressed because it is too large
View File


+ 462
- 0
java/src/com/google/i18n/phonenumbers/Phonenumber.java View File

@ -0,0 +1,462 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: phonenumber.proto
package com.google.i18n.phonenumbers;
public final class Phonenumber {
private Phonenumber() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
}
public static final class PhoneNumber extends
com.google.protobuf.GeneratedMessage {
// Use PhoneNumber.newBuilder() to construct.
private PhoneNumber() {
initFields();
}
private PhoneNumber(boolean noInit) {}
private static final PhoneNumber defaultInstance;
public static PhoneNumber getDefaultInstance() {
return defaultInstance;
}
public PhoneNumber getDefaultInstanceForType() {
return defaultInstance;
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return com.google.i18n.phonenumbers.Phonenumber.internal_static_i18n_phonenumbers_PhoneNumber_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return com.google.i18n.phonenumbers.Phonenumber.internal_static_i18n_phonenumbers_PhoneNumber_fieldAccessorTable;
}
// required int32 country_code = 1;
public static final int COUNTRY_CODE_FIELD_NUMBER = 1;
private boolean hasCountryCode;
private int countryCode_ = 0;
public boolean hasCountryCode() { return hasCountryCode; }
public int getCountryCode() { return countryCode_; }
// required uint64 national_number = 2;
public static final int NATIONAL_NUMBER_FIELD_NUMBER = 2;
private boolean hasNationalNumber;
private long nationalNumber_ = 0L;
public boolean hasNationalNumber() { return hasNationalNumber; }
public long getNationalNumber() { return nationalNumber_; }
// optional string extension = 3;
public static final int EXTENSION_FIELD_NUMBER = 3;
private boolean hasExtension;
private java.lang.String extension_ = "";
public boolean hasExtension() { return hasExtension; }
public java.lang.String getExtension() { return extension_; }
// optional bool italian_leading_zero = 4;
public static final int ITALIAN_LEADING_ZERO_FIELD_NUMBER = 4;
private boolean hasItalianLeadingZero;
private boolean italianLeadingZero_ = false;
public boolean hasItalianLeadingZero() { return hasItalianLeadingZero; }
public boolean getItalianLeadingZero() { return italianLeadingZero_; }
private void initFields() {
}
public final boolean isInitialized() {
if (!hasCountryCode) return false;
if (!hasNationalNumber) return false;
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
getSerializedSize();
if (hasCountryCode()) {
output.writeInt32(1, getCountryCode());
}
if (hasNationalNumber()) {
output.writeUInt64(2, getNationalNumber());
}
if (hasExtension()) {
output.writeString(3, getExtension());
}
if (hasItalianLeadingZero()) {
output.writeBool(4, getItalianLeadingZero());
}
getUnknownFields().writeTo(output);
}
private int memoizedSerializedSize = -1;
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
if (hasCountryCode()) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(1, getCountryCode());
}
if (hasNationalNumber()) {
size += com.google.protobuf.CodedOutputStream
.computeUInt64Size(2, getNationalNumber());
}
if (hasExtension()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(3, getExtension());
}
if (hasItalianLeadingZero()) {
size += com.google.protobuf.CodedOutputStream
.computeBoolSize(4, getItalianLeadingZero());
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(java.io.InputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input)) {
return builder.buildParsed();
} else {
return null;
}
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
return builder.buildParsed();
} else {
return null;
}
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static com.google.i18n.phonenumbers.Phonenumber.PhoneNumber parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder(com.google.i18n.phonenumbers.Phonenumber.PhoneNumber prototype) {
return newBuilder().mergeFrom(prototype);
}
public Builder toBuilder() { return newBuilder(this); }
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> {
private com.google.i18n.phonenumbers.Phonenumber.PhoneNumber result;
// Construct using com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.newBuilder()
private Builder() {}
private static Builder create() {
Builder builder = new Builder();
builder.result = new com.google.i18n.phonenumbers.Phonenumber.PhoneNumber();
return builder;
}
protected com.google.i18n.phonenumbers.Phonenumber.PhoneNumber internalGetResult() {
return result;
}
public Builder clear() {
if (result == null) {
throw new IllegalStateException(
"Cannot call clear() after build().");
}
result = new com.google.i18n.phonenumbers.Phonenumber.PhoneNumber();
return this;
}
public Builder clone() {
return create().mergeFrom(result);
}
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.getDescriptor();
}
public com.google.i18n.phonenumbers.Phonenumber.PhoneNumber getDefaultInstanceForType() {
return com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.getDefaultInstance();
}
public boolean isInitialized() {
return result.isInitialized();
}
public com.google.i18n.phonenumbers.Phonenumber.PhoneNumber build() {
if (result != null && !isInitialized()) {
throw newUninitializedMessageException(result);
}
return buildPartial();
}
private com.google.i18n.phonenumbers.Phonenumber.PhoneNumber buildParsed()
throws com.google.protobuf.InvalidProtocolBufferException {
if (!isInitialized()) {
throw newUninitializedMessageException(
result).asInvalidProtocolBufferException();
}
return buildPartial();
}
public com.google.i18n.phonenumbers.Phonenumber.PhoneNumber buildPartial() {
if (result == null) {
throw new IllegalStateException(
"build() has already been called on this Builder.");
}
com.google.i18n.phonenumbers.Phonenumber.PhoneNumber returnMe = result;
result = null;
return returnMe;
}
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof com.google.i18n.phonenumbers.Phonenumber.PhoneNumber) {
return mergeFrom((com.google.i18n.phonenumbers.Phonenumber.PhoneNumber)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(com.google.i18n.phonenumbers.Phonenumber.PhoneNumber other) {
if (other == com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.getDefaultInstance()) return this;
if (other.hasCountryCode()) {
setCountryCode(other.getCountryCode());
}
if (other.hasNationalNumber()) {
setNationalNumber(other.getNationalNumber());
}
if (other.hasExtension()) {
setExtension(other.getExtension());
}
if (other.hasItalianLeadingZero()) {
setItalianLeadingZero(other.getItalianLeadingZero());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder(
this.getUnknownFields());
while (true) {
int tag = input.readTag();
switch (tag) {
case 0:
this.setUnknownFields(unknownFields.build());
return this;
default: {
if (!parseUnknownField(input, unknownFields,
extensionRegistry, tag)) {
this.setUnknownFields(unknownFields.build());
return this;
}
break;
}
case 8: {
setCountryCode(input.readInt32());
break;
}
case 16: {
setNationalNumber(input.readUInt64());
break;
}
case 26: {
setExtension(input.readString());
break;
}
case 32: {
setItalianLeadingZero(input.readBool());
break;
}
}
}
}
// required int32 country_code = 1;
public boolean hasCountryCode() {
return result.hasCountryCode();
}
public int getCountryCode() {
return result.getCountryCode();
}
public Builder setCountryCode(int value) {
result.hasCountryCode = true;
result.countryCode_ = value;
return this;
}
public Builder clearCountryCode() {
result.hasCountryCode = false;
result.countryCode_ = 0;
return this;
}
// required uint64 national_number = 2;
public boolean hasNationalNumber() {
return result.hasNationalNumber();
}
public long getNationalNumber() {
return result.getNationalNumber();
}
public Builder setNationalNumber(long value) {
result.hasNationalNumber = true;
result.nationalNumber_ = value;
return this;
}
public Builder clearNationalNumber() {
result.hasNationalNumber = false;
result.nationalNumber_ = 0L;
return this;
}
// optional string extension = 3;
public boolean hasExtension() {
return result.hasExtension();
}
public java.lang.String getExtension() {
return result.getExtension();
}
public Builder setExtension(java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
result.hasExtension = true;
result.extension_ = value;
return this;
}
public Builder clearExtension() {
result.hasExtension = false;
result.extension_ = getDefaultInstance().getExtension();
return this;
}
// optional bool italian_leading_zero = 4;
public boolean hasItalianLeadingZero() {
return result.hasItalianLeadingZero();
}
public boolean getItalianLeadingZero() {
return result.getItalianLeadingZero();
}
public Builder setItalianLeadingZero(boolean value) {
result.hasItalianLeadingZero = true;
result.italianLeadingZero_ = value;
return this;
}
public Builder clearItalianLeadingZero() {
result.hasItalianLeadingZero = false;
result.italianLeadingZero_ = false;
return this;
}
// @@protoc_insertion_point(builder_scope:i18n.phonenumbers.PhoneNumber)
}
static {
defaultInstance = new PhoneNumber(true);
com.google.i18n.phonenumbers.Phonenumber.internalForceInit();
defaultInstance.initFields();
}
// @@protoc_insertion_point(class_scope:i18n.phonenumbers.PhoneNumber)
}
private static com.google.protobuf.Descriptors.Descriptor
internal_static_i18n_phonenumbers_PhoneNumber_descriptor;
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_i18n_phonenumbers_PhoneNumber_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\021phonenumber.proto\022\021i18n.phonenumbers\"m" +
"\n\013PhoneNumber\022\024\n\014country_code\030\001 \002(\005\022\027\n\017n" +
"ational_number\030\002 \002(\004\022\021\n\textension\030\003 \001(\t\022" +
"\034\n\024italian_leading_zero\030\004 \001(\010B\036\n\034com.goo" +
"gle.i18n.phonenumbers"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
public com.google.protobuf.ExtensionRegistry assignDescriptors(
com.google.protobuf.Descriptors.FileDescriptor root) {
descriptor = root;
internal_static_i18n_phonenumbers_PhoneNumber_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_i18n_phonenumbers_PhoneNumber_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_i18n_phonenumbers_PhoneNumber_descriptor,
new java.lang.String[] { "CountryCode", "NationalNumber", "Extension", "ItalianLeadingZero", },
com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.class,
com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.Builder.class);
return null;
}
};
com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
}, assigner);
}
public static void internalForceInit() {}
// @@protoc_insertion_point(outer_class_scope)
}

+ 209
- 0
java/src/com/google/i18n/phonenumbers/phonemetadata.proto View File

@ -0,0 +1,209 @@
/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Definition of protocol buffer for holding metadata for international
// telephone numbers.
// @author Shaopeng Jia
syntax = "proto2";
option java_package = "com.google.i18n.phonenumbers";
package i18n.phonenumbers;
message NumberFormat {
// pattern is a regex that is used to match the national (significant)
// number. For example, the pattern "(20)(\d{4})(\d{4})" will match number
// "2070313000", which is the national (significant) number for Google London.
// Note the presence of the parentheses, which are capturing groups what
// specifies the grouping of numbers.
required string pattern = 1;
// format specifies how the national (significant) number matched by
// pattern should be formatted.
// Using the same example as above, format could contain "$1 $2 $3",
// meaning that the number should be formatted as "20 7031 3000".
// Each $x are replaced by the numbers captured by group x in the
// regex specified by pattern.
required string format = 2;
// leadingDigits is a regex that is used to match up to the first four digits
// of the national (significant) number. When the match is successful, the
// accompanying pattern and format should be used to format this number. For
// example, if leading_digits="[1-3]|44", then all the national numbers
// starting with 1, 2, 3 or 44 should be formatted using the accompanying
// pattern and format.
optional string leading_digits = 3;
// This field specifies how the national prefix ($NP) together with the first
// group ($FG) in the national significant number should be formatted in
// the NATIONAL format when a national prefix exists for a certain country.
// When present, it overrides the national_prefix_formatting_rule specified
// in PhoneNumberDesc. See the comment in PhoneNumberDesc for more information
// on how this rule is specified.
optional string national_prefix_formatting_rule = 4;
}
message PhoneNumberDesc {
// The national_number_pattern is the pattern that a valid national
// significant number would match. This specifies information such as its
// total length and leading digits.
optional string national_number_pattern = 2;
// The possible_number_pattern represents what a potentially valid phone
// number for this region may be written as. This is a superset of the
// national_number_pattern above and includes numbers that have the area code
// omitted. Typically the only restrictions here are in the number of digits.
// This could be used to highlight tokens in a text that may be a phone
// number, or to quickly prune numbers that could not possibly be a phone
// number for this locale.
optional string possible_number_pattern = 3;
// An example national significant number for the specific type. It should
// not contain any formatting information.
optional string example_number = 6;
}
message PhoneMetadata {
// The general_desc contains information which is a superset of descriptions
// for all types of phone numbers. If any element is missing in the
// description of a specific type in the XML file, the element will inherit
// from its counterpart in the general_desc. Every locale is assumed to have
// fixed line and mobile numbers - if these types are missing in the XML
// file, they will inherit all fields from the general_desc. For all other
// types, if the whole type is missing in the xml file, it will be given a
// national_number_pattern of "NA" and a possible_number_pattern of "NA".
required PhoneNumberDesc general_desc = 1;
required PhoneNumberDesc fixed_line = 2;
required PhoneNumberDesc mobile = 3;
required PhoneNumberDesc toll_free = 4;
required PhoneNumberDesc premium_rate = 5;
required PhoneNumberDesc shared_cost = 6;
required PhoneNumberDesc personal_number = 7;
required PhoneNumberDesc voip = 8;
// The ISO 3166-1 alpha-2 representation of a country/region
required string id = 9;
// The country calling code that one would dial from overseas when trying to
// dial a phone number in this country. For example, this would be "64" for
// New Zealand.
required int32 country_code = 10;
// The international_prefix of country A is the number that needs to be
// dialled from country A to another country (country B). This is followed
// by the country code for country B. Note that some countries may have more
// than one international prefix, and for those cases, a regular expression
// matching the international prefixes will be stored in this field.
required string international_prefix = 11;
// If more than one international prefix is present, a preferred prefix can
// be specified here for out-of-country formatting purposes. If this field is
// not present, and multiple international prefixes are present, then "+"
// will be used instead.
optional string preferred_international_prefix = 17;
// The national prefix of country A is the number that needs to be dialled
// before the national significant number when dialling internally. This
// would not be dialled when dialling internationally. For example, in New
// Zealand, the number that would be locally dialled as 09 345 3456 would be
// dialled from overseas as +64 9 345 3456. In this case, 0 is the national
// prefix.
optional string national_prefix = 12;
// The preferred prefix when specifying an extension in this country. This is
// used for formatting only, and if this is not specified, a suitable default
// should be used instead. For example, if you wanted extensions to be
// formatted in the following way:
// 1 (365) 345 445 ext. 2345
// " ext. " should be the preferred extension prefix.
optional string preferred_extn_prefix = 13;
// This field is used for cases where the national prefix of a country
// contains a carrier selection code, and is written in the form of a
// regular expression. For example, to dial the number 2222-2222 in
// Fortaleza, Brazil (area code 85) using the long distance carrier Oi
// (selection code 31), one would dial 0 31 85 2222 2222. Assuming the
// only other possible carrier selection code is 32, the field will
// contain "03[12]".
//
// When it is missing from the XML file, this field inherits the value of
// national_prefix, if that is present.
optional string national_prefix_for_parsing = 15;
// This field is only populated and used under very rare situations.
// For example, mobile numbers in Argentina are written in two completely
// different ways when dialed in-country and out-of-country
// (e.g. 0343 15 555 1212 is exactly the same number as +54 9 343 555 1212).
// This field is used together with national_prefix_for_parsing to transform
// the number into a particular representation for storing in the phonenumber
// proto buffer in those rare cases.
optional string national_prefix_transform_rule = 16;
// Specifies whether the mobile and fixed-line patterns are the same or not.
// This is used to speed up determining phone number type in countries where
// these two types of phone numbers can never be distinguished.
optional bool same_mobile_and_fixed_line_pattern = 18 [default=false];
// Note that the number format here is used for formatting only, not parsing.
// Hence all the varied ways a user *may* write a number need not be recorded
// - just the ideal way we would like to format it for them. When this element
// is absent, the national significant number will be formatted as a whole
// without any formatting applied.
//
// When formatting, the library goes through the list of formats from the
// beginning and the first successful match is used to do the formatting.
// A match is successful if the phone number being formatted starts with
// digits matching the leadingDigits and the number itself matches the
// corresponding pattern. However, AsYouTypeFormatter goes through the whole
// list and selects formats whose leadingDigits match what has been typed
// so far. Therefore, having more specific leadingDigits improves the
// performance of AsYouTypeFormatter in terms of speed.
repeated NumberFormat number_format = 19;
// This field is populated only when the national significant number is
// formatted differently when it forms part of the INTERNATIONAL format
// and NATIONAL format. A case in point is mobile numbers in Argentina:
// The number, which would be written in INTERNATIONAL format as
// +54 9 343 555 1212, will be written as 0343 15 555 1212 for NATIONAL
// format. In this case, the prefix 9 is inserted when dialling from
// overseas, but otherwise the prefix 0 and the carrier selection code
// 15 (inserted after the area code of 343) is used.
repeated NumberFormat intl_number_format = 20;
// This field specifies how the national prefix ($NP) together with the first
// group ($FG) in the national significant number should be formatted in
// the NATIONAL format when a national prefix exists for a certain country.
// For example, when this field contains "($NP$FG)", a number from Beijing,
// China (whose $NP = 0), which would by default be formatted without
// national prefix as 10 1234 5678 in NATIONAL format, will instead be
// formatted as (010) 1234 5678; to format it as (0)10 1234 5678, the field
// would contain "($NP)$FG". Note $FG should always be present in this field,
// but $NP can be omitted. For example, having "$FG" could indicate the
// number should be formatted in NATIONAL format without the national prefix.
// This is commonly used to override the rule from generalDesc.
//
// When this field is missing, a number will be formatted without national
// prefix in NATIONAL format. This field does not affect how a number
// is formatted in other formats, such as INTERNATIONAL.
//
// This field applies to all numberFormats unless overridden by the
// national_prefix_formatting_rule in a specific numberFormat.
optional string national_prefix_formatting_rule = 21;
}
message PhoneMetadataCollection {
repeated PhoneMetadata metadata = 1;
}

+ 71
- 0
java/src/com/google/i18n/phonenumbers/phonenumber.proto View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Definition of protocol buffer for representing international telephone numbers.
// @author Shaopeng Jia
syntax = "proto2";
option java_package = "com.google.i18n.phonenumbers";
package i18n.phonenumbers;
message PhoneNumber {
required int32 country_code = 1;
// National (significant) Number is defined in International Telecommunication Union Recommendation
// E.164. It is a language/country-neutral representation of a phone number at a country level. For
// countries which have the concept of Area Code, the National (significant) Number contains the
// area code. It contains a maximum number of digits which equal to 15 - n, where n is the number of
// digits of the country code. Take note that National (significant) Number does not contain
// National(trunk) prefix. Obviously, as a uint64, it will never contain any formatting (hypens,
// spaces, parentheses), nor any alphanumeric spellings.
required uint64 national_number = 2;
// Extension is not standardized in ITU recommendations, except for being defined as a series of
// numbers with a maximum length of 40 digits. It is defined as a string here to accommodate for the
// possible use of a leading zero in the extension (organizations have complete freedom to do so,
// as there is no standard defined). However, only ASCII digits should be stored here.
optional string extension = 3;
// The leading zero in the national (significant) number of an Italian phone number has a special
// meaning. Unlike the rest of the world, it indicates the number is a fixed-line number. There have
// been plans to migrate fixed-line numbers to start with the digit two since December 2000, but it
// has not happened yet. See http://en.wikipedia.org/wiki/%2B39 for more details.
//
// This field can be safely ignored (no need to set it) if you are not dealing with Italian
// phone numbers. For an Italian phone number, if its national (significant) number starts
// with the digit zero, set this flag to true.
optional bool italian_leading_zero = 4;
}
// Examples
//
// Google MTV, +1 650-253-0000, (650) 253-0000
// country_code: 1
// national_number: 6502530000
//
// Google Paris, +33 (0)1 42 68 53 00, 01 42 68 53 00
// country_code: 33
// national_number: 142685300
//
// Google Beijing, +86-10-62503000, (010) 62503000
// country_code: 86
// national_number: 1062503000
//
// Google Italy, +39 02-36618 300, 02-36618 300
// country_code: 39
// national_number: 236618300
// italian_leading_zero: true

Loading…
Cancel
Save