summaryrefslogtreecommitdiff
path: root/java/src/com
diff options
context:
space:
mode:
authorShaopeng Jia <shaopengjia@google.com>2011-03-22 14:22:53 +0100
committerShaopeng Jia <shaopengjia@google.com>2011-03-22 14:56:26 +0100
commit52699e08e855fb0957944b4e73358ad9e0007c0c (patch)
tree54d545415d88dca116dbe3ad15e8efca97688904 /java/src/com
parentb93a7356a018d48143ad7e6adfe9544dc4b89d19 (diff)
downloadlibphonenumber-52699e08e855fb0957944b4e73358ad9e0007c0c.tar.gz
Refresh external/libphonenumber to r136.
Change-Id: I5a44a2d15071d319a273a078ff85c25877b174c0
Diffstat (limited to 'java/src/com')
-rw-r--r--java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java33
-rw-r--r--java/src/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMap.java8
-rw-r--r--java/src/com/google/i18n/phonenumbers/PhoneNumberMatch.java124
-rw-r--r--java/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java336
-rw-r--r--java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java234
-rw-r--r--java/src/com/google/i18n/phonenumbers/Phonenumber.java37
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_ACbin0 -> 218 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BFbin375 -> 383 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BObin516 -> 530 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BRbin683 -> 683 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CLbin864 -> 884 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CObin818 -> 832 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CRbin375 -> 419 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DKbin404 -> 410 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FObin368 -> 399 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GEbin652 -> 695 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KRbin1493 -> 1568 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KWbin452 -> 453 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LAbin458 -> 391 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LUbin1404 -> 1460 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MUbin424 -> 440 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SCbin627 -> 623 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SHbin146 -> 241 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TRbin343 -> 661 bytes
-rw-r--r--java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VEbin392 -> 400 bytes
25 files changed, 698 insertions, 74 deletions
diff --git a/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java b/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
index b0e500de..11b8ba08 100644
--- a/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
+++ b/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
@@ -55,7 +55,7 @@ public class AsYouTypeFormatter {
// A pattern that is used to match character classes in regular expressions. An example of a
// character class is [1-4].
- private final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]");
+ private static final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]");
// Any digit in a regular expression that actually denotes a digit. For example, in the regular
// expression 80[0-2]\d{6,10}, the first 2 digits (8 and 0) are standalone digits, but the rest
// are not.
@@ -89,8 +89,8 @@ public class AsYouTypeFormatter {
private RegexCache regexCache = new RegexCache(64);
/**
- * Constructs a light-weight formatter which does no formatting, but outputs exactly what is
- * fed into the inputDigit method.
+ * Constructs an as-you-type formatter. Should be obtained from {@link
+ * PhoneNumberUtil#getAsYouTypeFormatter}.
*
* @param regionCode the country/region where the phone number is being entered
*/
@@ -102,6 +102,11 @@ public class AsYouTypeFormatter {
private void initializeCountrySpecificInfo(String regionCode) {
currentMetaData = phoneUtil.getMetadataForRegion(regionCode);
+ if (currentMetaData == null) {
+ // Set to a default instance of the metadata. This allows us to function with an incorrect
+ // region code, even if formatting only works for numbers specified with "+".
+ currentMetaData = new PhoneMetadata().setInternationalPrefix("NA");
+ }
nationalPrefixForParsing =
regexCache.getPatternForRegex(currentMetaData.getNationalPrefixForParsing());
internationalPrefix =
@@ -170,8 +175,12 @@ public class AsYouTypeFormatter {
// Replace any standalone digit (not the one in d{}) with \d
numberPattern = STANDALONE_DIGIT_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
formattingTemplate.setLength(0);
- formattingTemplate.append(getFormattingTemplate(numberPattern, numberFormat));
- return true;
+ String tempTemplate = getFormattingTemplate(numberPattern, numberFormat);
+ if (tempTemplate.length() > nationalNumber.length()) {
+ formattingTemplate.append(tempTemplate);
+ return true;
+ }
+ return false;
}
// Gets a formatting template which could be used to efficiently format a partial number where
@@ -236,7 +245,7 @@ public class AsYouTypeFormatter {
return currentOutput;
}
- @SuppressWarnings(value = "fallthrough")
+ @SuppressWarnings("fallthrough")
private String inputDigitWithOptionToRememberPosition(char nextChar, boolean rememberPosition) {
accruedInput.append(nextChar);
if (rememberPosition) {
@@ -323,8 +332,7 @@ public class AsYouTypeFormatter {
if (!ableToFormat) {
return originalPosition;
}
- int accruedInputIndex = 0;
- int currentOutputIndex = 0;
+ int accruedInputIndex = 0, currentOutputIndex = 0;
int currentOutputLength = currentOutput.length();
while (accruedInputIndex < positionToRemember && currentOutputIndex < currentOutputLength) {
if (accruedInputWithoutFormatting.charAt(accruedInputIndex) ==
@@ -466,8 +474,13 @@ public class AsYouTypeFormatter {
formattingTemplate.replace(0, tempTemplate.length(), tempTemplate);
lastMatchPosition = digitMatcher.start();
return formattingTemplate.substring(0, lastMatchPosition + 1);
- } else { // More digits are entered than we could handle.
- ableToFormat = false;
+ } else {
+ if (possibleFormats.size() == 1) {
+ // More digits are entered than we could handle, and there are no other valid patterns to
+ // try.
+ ableToFormat = false;
+ } // else, we just reset the formatting pattern.
+ currentFormattingPattern = "";
return accruedInput.toString();
}
}
diff --git a/java/src/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMap.java b/java/src/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMap.java
index 86e7f0b1..8d4b1f9c 100644
--- a/java/src/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMap.java
+++ b/java/src/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMap.java
@@ -30,10 +30,10 @@ public class CountryCodeToRegionCodeMap {
// countries sharing a calling code, such as the NANPA countries, the one
// indicated with "isMainCountryForCode" in the metadata should be first.
static Map<Integer, List<String>> getCountryCodeToRegionCodeMap() {
- // The capacity is set to 272 as there are 204 different country codes,
+ // The capacity is set to 273 as there are 205 different country codes,
// and this offers a load factor of roughly 0.75.
Map<Integer, List<String>> countryCodeToRegionCodeMap =
- new HashMap<Integer, List<String>>(272);
+ new HashMap<Integer, List<String>>(273);
ArrayList<String> listWithRegionCode;
@@ -373,6 +373,10 @@ public class CountryCodeToRegionCodeMap {
countryCodeToRegionCodeMap.put(246, listWithRegionCode);
listWithRegionCode = new ArrayList<String>(1);
+ listWithRegionCode.add("AC");
+ countryCodeToRegionCodeMap.put(247, listWithRegionCode);
+
+ listWithRegionCode = new ArrayList<String>(1);
listWithRegionCode.add("SC");
countryCodeToRegionCodeMap.put(248, listWithRegionCode);
diff --git a/java/src/com/google/i18n/phonenumbers/PhoneNumberMatch.java b/java/src/com/google/i18n/phonenumbers/PhoneNumberMatch.java
new file mode 100644
index 00000000..b00a0e18
--- /dev/null
+++ b/java/src/com/google/i18n/phonenumbers/PhoneNumberMatch.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 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.Phonenumber.PhoneNumber;
+
+import java.util.Arrays;
+
+/**
+ * The immutable match of a phone number within a piece of text. Matches may be found using
+ * {@link PhoneNumberUtil#findNumbers}.
+ *
+ * <p>A match consists of the {@linkplain #number() phone number} as well as the
+ * {@linkplain #start() start} and {@linkplain #end() end} offsets of the corresponding subsequence
+ * of the searched text. Use {@link #rawString()} to obtain a copy of the matched subsequence.
+ *
+ * <p>The following annotated example clarifies the relationship between the searched text, the
+ * match offsets, and the parsed number:
+
+ * <pre>
+ * CharSequence text = "Call me at +1 425 882-8080 for details.";
+ * RegionCode country = RegionCode.US;
+ * PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ *
+ * // Find the first phone number match:
+ * PhoneNumberMatch m = util.findNumbers(text, country).iterator().next();
+ *
+ * // rawString() contains the phone number as it appears in the text.
+ * "+1 425 882-8080".equals(m.rawString());
+ *
+ * // start() and end() define the range of the matched subsequence.
+ * CharSequence subsequence = text.subSequence(m.start(), m.end());
+ * "+1 425 882-8080".contentEquals(subsequence);
+ *
+ * // number() returns the the same result as PhoneNumberUtil.{@link PhoneNumberUtil#parse parse()}
+ * // invoked on rawString().
+ * util.parse(m.rawString(), country).equals(m.number());
+ * </pre>
+ *
+ * @author Tom Hofmann
+ */
+public final class PhoneNumberMatch {
+ /** The start index into the text. */
+ private final int start;
+ /** The raw substring matched. */
+ private final String match;
+ /** The matched phone number. */
+ private final PhoneNumber number;
+
+ /**
+ * Creates a new match.
+ *
+ * @param start the start index into the target text
+ * @param match the matched substring of the target text
+ * @param number the matched phone number
+ */
+ PhoneNumberMatch(int start, String match, PhoneNumber number) {
+ if (start < 0) {
+ throw new IllegalArgumentException("Start index must be >= 0.");
+ }
+ if (match == null || number == null) {
+ throw new NullPointerException();
+ }
+ this.start = start;
+ this.match = match;
+ this.number = number;
+ }
+
+ /** Returns the phone number matched by the receiver. */
+ public PhoneNumber number() {
+ return number;
+ }
+
+ /** Returns the start index of the matched phone number within the searched text. */
+ public int start() {
+ return start;
+ }
+
+ /** Returns the exclusive end index of the matched phone number within the searched text. */
+ public int end() {
+ return start + match.length();
+ }
+
+ /** Returns the raw string matched as a phone number in the searched text. */
+ public String rawString() {
+ return match;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(new Object[]{start, match, number});
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof PhoneNumberMatch)) {
+ return false;
+ }
+ PhoneNumberMatch other = (PhoneNumberMatch) obj;
+ return match.equals(other.match) && (start == other.start) && number.equals(other.number);
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneNumberMatch [" + start() + "," + end() + ") " + match;
+ }
+}
diff --git a/java/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java b/java/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java
new file mode 100644
index 00000000..1905b5e4
--- /dev/null
+++ b/java/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2011 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.PhoneNumberUtil.Leniency;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A stateful class that finds and extracts telephone numbers from {@linkplain CharSequence text}.
+ * Instances can be created using the {@linkplain PhoneNumberUtil#findNumbers factory methods} in
+ * {@link PhoneNumberUtil}.
+ *
+ * <p>Vanity numbers (phone numbers using alphabetic digits such as <tt>1-800-SIX-FLAGS</tt> are
+ * not found.
+ *
+ * <p>This class is not thread-safe.
+ *
+ * @author Tom Hofmann
+ */
+final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
+ /**
+ * The phone number pattern used by {@link #find}, similar to
+ * {@code PhoneNumberUtil.VALID_PHONE_NUMBER}, but with the following differences:
+ * <ul>
+ * <li>All captures are limited in order to place an upper bound to the text matched by the
+ * pattern.
+ * <ul>
+ * <li>Leading punctuation / plus signs are limited.
+ * <li>Consecutive occurrences of punctuation are limited.
+ * <li>Number of digits is limited.
+ * </ul>
+ * <li>No whitespace is allowed at the start or end.
+ * <li>No alpha digits (vanity numbers such as 1-800-SIX-FLAGS) are currently supported.
+ * </ul>
+ */
+ private static final Pattern PATTERN;
+ /**
+ * A phone number pattern that does not allow whitespace as punctuation. This pattern is only used
+ * in a second attempt to find a phone number occurring in the context of other numbers, such as
+ * when the preceding or following token is a zip code.
+ */
+ private static final Pattern INNER;
+ /**
+ * Matches strings that look like publication pages. Example:
+ * <pre>Computing Complete Answers to Queries in the Presence of Limited Access Patterns.
+ * Chen Li. VLDB J. 12(3): 211-227 (2003).</pre>
+ *
+ * The string "211-227 (2003)" is not a telephone number.
+ */
+ private static final Pattern PUB_PAGES = Pattern.compile("\\d{1,5}-+\\d{1,5}\\s{0,4}\\(\\d{1,4}");
+
+ static {
+ /* Builds the PATTERN and INNER regular expression patterns. The building blocks below
+ * exist to make the patterns more easily understood. */
+
+ /* Limit on the number of leading (plus) characters. */
+ String leadLimit = limit(0, 2);
+ /* Limit on the number of consecutive punctuation characters. */
+ String punctuationLimit = limit(0, 4);
+ /* The maximum number of digits allowed in a digit-separated block. As we allow all digits in a
+ * single block, set high enough to accommodate the entire national number and the international
+ * country code. */
+ int digitBlockLimit =
+ PhoneNumberUtil.MAX_LENGTH_FOR_NSN + PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE;
+ /* Limit on the number of blocks separated by punctuation. Use digitBlockLimit since in some
+ * formats use spaces to separate each digit. */
+ String blockLimit = limit(0, digitBlockLimit);
+
+ /* Same as {@link PhoneNumberUtil#VALID_PUNCTUATION} but without space characters. */
+ String nonSpacePunctuationChars = removeSpace(PhoneNumberUtil.VALID_PUNCTUATION);
+ /* A punctuation sequence without white space. */
+ String nonSpacePunctuation = "[" + nonSpacePunctuationChars + "]" + punctuationLimit;
+ /* A punctuation sequence allowing white space. */
+ String punctuation = "[" + PhoneNumberUtil.VALID_PUNCTUATION + "]" + punctuationLimit;
+ /* A digits block without punctuation. */
+ String digitSequence = "\\p{Nd}" + limit(1, digitBlockLimit);
+ /* Punctuation that may be at the start of a phone number - brackets and plus signs. */
+ String leadClass = "[(\\[" + PhoneNumberUtil.PLUS_CHARS + "]";
+
+ /* Phone number pattern allowing optional punctuation. */
+ PATTERN = Pattern.compile(
+ "(?:" + leadClass + punctuation + ")" + leadLimit +
+ digitSequence + "(?:" + punctuation + digitSequence + ")" + blockLimit +
+ "(?:" + PhoneNumberUtil.KNOWN_EXTN_PATTERNS + ")?",
+ PhoneNumberUtil.REGEX_FLAGS);
+
+ /* Phone number pattern with no whitespace allowed. */
+ INNER = Pattern.compile(
+ leadClass + leadLimit +
+ digitSequence + "(?:" + nonSpacePunctuation + digitSequence + ")" + blockLimit,
+ PhoneNumberUtil.REGEX_FLAGS);
+ }
+
+ /** Returns a regular expression quantifier with an upper and lower limit. */
+ private static String limit(int lower, int upper) {
+ if ((lower < 0) || (upper <= 0) || (upper < lower)) {
+ throw new IllegalArgumentException();
+ }
+ return "{" + lower + "," + upper + "}";
+ }
+
+ /**
+ * Returns a copy of {@code characters} with any {@linkplain Character#isSpaceChar space}
+ * characters removed.
+ */
+ private static String removeSpace(String characters) {
+ StringBuilder builder = new StringBuilder(characters.length());
+ int i = 0;
+ while (i < characters.length()) {
+ int codePoint = characters.codePointAt(i);
+ if (!Character.isSpaceChar(codePoint)) {
+ builder.appendCodePoint(codePoint);
+ }
+ i += Character.charCount(codePoint);
+ }
+ return builder.toString();
+ }
+
+ /** The potential states of a PhoneNumberMatcher. */
+ private enum State {
+ NOT_READY, READY, DONE
+ }
+
+ /** The phone number utility. */
+ private final PhoneNumberUtil util;
+ /** The text searched for phone numbers. */
+ private final CharSequence text;
+ /**
+ * The region (country) to assume for phone numbers without an international prefix, possibly
+ * null.
+ */
+ private final String preferredRegion;
+ /** The degree of validation requested. */
+ private final Leniency leniency;
+ /** The maximum number of retries after matching an invalid number. */
+ private long maxTries;
+
+ /** The iteration tristate. */
+ private State state = State.NOT_READY;
+ /** The last successful match, null unless in {@link State#READY}. */
+ private PhoneNumberMatch lastMatch = null;
+ /** The next index to start searching at. Undefined in {@link State#DONE}. */
+ private int searchIndex = 0;
+
+ /**
+ * Creates a new instance. See the factory methods in {@link PhoneNumberUtil} on how to obtain a
+ * new instance.
+ *
+ * @param util the phone number util to use
+ * @param text the character sequence that we will search, null for no text
+ * @param country the ISO 3166-1 two-letter country code indicating the country to assume for
+ * phone numbers not written in international format (with a leading plus, or
+ * with the international dialing prefix of the specified region). May be null or
+ * "ZZ" if only numbers with a leading plus should be considered.
+ * @param leniency the leniency to use when evaluating candidate phone numbers
+ * @param maxTries the maximum number of invalid numbers to try before giving up on the text.
+ * This is to cover degenerate cases where the text has a lot of false positives
+ * in it. Must be {@code >= 0}.
+ */
+ PhoneNumberMatcher(PhoneNumberUtil util, CharSequence text, String country, Leniency leniency,
+ long maxTries) {
+
+ if ((util == null) || (leniency == null)) {
+ throw new NullPointerException();
+ }
+ if (maxTries < 0) {
+ throw new IllegalArgumentException();
+ }
+ this.util = util;
+ this.text = (text != null) ? text : "";
+ this.preferredRegion = country;
+ this.leniency = leniency;
+ this.maxTries = maxTries;
+ }
+
+ public boolean hasNext() {
+ if (state == State.NOT_READY) {
+ lastMatch = find(searchIndex);
+ if (lastMatch == null) {
+ state = State.DONE;
+ } else {
+ searchIndex = lastMatch.end();
+ state = State.READY;
+ }
+ }
+ return state == State.READY;
+ }
+
+ public PhoneNumberMatch next() {
+ // Check the state and find the next match as a side-effect if necessary.
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ // Don't retain that memory any longer than necessary.
+ PhoneNumberMatch result = lastMatch;
+ lastMatch = null;
+ state = State.NOT_READY;
+ return result;
+ }
+
+ /**
+ * Attempts to find the next subsequence in the searched sequence on or after {@code searchIndex}
+ * that represents a phone number. Returns the next match, null if none was found.
+ *
+ * @param index the search index to start searching at
+ * @return the phone number match found, null if none can be found
+ */
+ private PhoneNumberMatch find(int index) {
+ Matcher matcher = PATTERN.matcher(text);
+ while ((maxTries > 0) && matcher.find(index)) {
+ int start = matcher.start();
+ CharSequence candidate = text.subSequence(start, matcher.end());
+
+ // Check for extra numbers at the end.
+ // TODO: This is the place to start when trying to support extraction of multiple phone number
+ // from split notations (+41 79 123 45 67 / 68).
+ candidate = trimAfterFirstMatch(PhoneNumberUtil.SECOND_NUMBER_START_PATTERN, candidate);
+
+ PhoneNumberMatch match = extractMatch(candidate, start);
+ if (match != null) {
+ return match;
+ }
+
+ index = start + candidate.length();
+ maxTries--;
+ }
+
+ return null;
+ }
+
+ /**
+ * Trims away any characters after the first match of {@code pattern} in {@code candidate},
+ * returning the trimmed version.
+ */
+ private static CharSequence trimAfterFirstMatch(Pattern pattern, CharSequence candidate) {
+ Matcher trailingCharsMatcher = pattern.matcher(candidate);
+ if (trailingCharsMatcher.find()) {
+ candidate = candidate.subSequence(0, trailingCharsMatcher.start());
+ }
+ return candidate;
+ }
+
+ /**
+ * Attempts to extract a match from a {@code candidate} character sequence.
+ *
+ * @param candidate the candidate text that might contain a phone number
+ * @param offset the offset of {@code candidate} within {@link #text}
+ * @return the match found, null if none can be found
+ */
+ private PhoneNumberMatch extractMatch(CharSequence candidate, int offset) {
+ // Skip a match that is more likely a publication page reference.
+ if (PUB_PAGES.matcher(candidate).find()) {
+ return null;
+ }
+
+ // Try to come up with a valid match given the entire candidate.
+ String rawString = candidate.toString();
+ PhoneNumberMatch match = parseAndVerify(rawString, offset);
+ if (match != null) {
+ return match;
+ }
+
+ // If that failed, try to find an inner match without white space.
+ return extractInnerMatch(rawString, offset);
+ }
+
+ /**
+ * Attempts to extract a match from {@code candidate} using the {@link #INNER} pattern.
+ *
+ * @param candidate the candidate text that might contain a phone number
+ * @param offset the offset of {@code candidate} within {@link #text}
+ * @return the match found, null if none can be found
+ */
+ private PhoneNumberMatch extractInnerMatch(String candidate, int offset) {
+ int index = 0;
+ Matcher matcher = INNER.matcher(candidate);
+ while ((maxTries > 0) && matcher.find(index)) {
+ String innerCandidate = candidate.substring(matcher.start(), matcher.end());
+ PhoneNumberMatch match = parseAndVerify(innerCandidate, offset + matcher.start());
+ if (match != null) {
+ return match;
+ }
+ maxTries--;
+ index = matcher.end();
+ }
+ return null;
+ }
+
+ /**
+ * Parses a phone number from the {@code candidate} using {@link PhoneNumberUtil#parse} and
+ * verifies it matches the requested {@link #leniency}. If parsing and verification succeed, a
+ * corresponding {@link PhoneNumberMatch} is returned, otherwise this method returns null.
+ *
+ * @param candidate the candidate match
+ * @param offset the offset of {@code candidate} within {@link #text}
+ * @return the parsed and validated phone number match, or null
+ */
+ private PhoneNumberMatch parseAndVerify(String candidate, int offset) {
+ try {
+ PhoneNumber number = util.parse(candidate, preferredRegion);
+ if (leniency.verify(number, util)) {
+ return new PhoneNumberMatch(offset, candidate, number);
+ }
+ } catch (NumberParseException e) {
+ // ignore and continue
+ }
+ return null;
+ }
+
+ /**
+ * Always throws {@link UnsupportedOperationException} as removal is not supported.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
index 9f003920..a0f18572 100644
--- a/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
+++ b/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
@@ -23,14 +23,15 @@ import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -56,8 +57,6 @@ public class PhoneNumberUtil {
static final int MAX_LENGTH_COUNTRY_CODE = 3;
static final String META_DATA_FILE_PREFIX =
"/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto";
- static final String COUNTRY_CODE_TO_REGION_CODE_MAP_CLASS_NAME =
- "CountryCodeToRegionCodeMap";
private String currentFilePrefix = META_DATA_FILE_PREFIX;
private static final Logger LOGGER = Logger.getLogger(PhoneNumberUtil.class.getName());
@@ -380,6 +379,36 @@ public class PhoneNumberUtil {
}
/**
+ * Leniency when {@linkplain PhoneNumberUtil#findNumbers finding} potential phone numbers in text
+ * segments.
+ */
+ public enum Leniency {
+ /**
+ * Phone numbers accepted are {@linkplain PhoneNumberUtil#isPossibleNumber(PhoneNumber)
+ * possible}, but not necessarily {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid}.
+ */
+ POSSIBLE {
+ @Override
+ boolean verify(PhoneNumber number, PhoneNumberUtil util) {
+ return util.isPossibleNumber(number);
+ }
+ },
+ /**
+ * Phone numbers accepted are {@linkplain PhoneNumberUtil#isPossibleNumber(PhoneNumber)
+ * possible} and {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid}.
+ */
+ VALID {
+ @Override
+ boolean verify(PhoneNumber number, PhoneNumberUtil util) {
+ return util.isValidNumber(number);
+ }
+ };
+
+ /** Returns true if {@code number} is a verified number according to this leniency. */
+ abstract boolean verify(PhoneNumber number, PhoneNumberUtil util);
+ }
+
+ /**
* This class implements a singleton, so the only constructor is private.
*/
private PhoneNumberUtil() {
@@ -551,7 +580,7 @@ public class PhoneNumberUtil {
* - some geographical numbers have no area codes.
*
* @param number the PhoneNumber object for which clients want to know the length of the area
- * code in the national_number field.
+ * code.
* @return the length of area code of the PhoneNumber object passed in.
*/
public int getLengthOfGeographicalAreaCode(PhoneNumber number) {
@@ -829,6 +858,17 @@ public class PhoneNumberUtil {
return formattedNumber.toString();
}
+ /**
+ * Formats a phone number in national format for dialing using the carrier as specified in the
+ * carrierCode. The carrierCode will always be used regardless of whether the phone number already
+ * has a preferred domestic carrier code stored. If carrierCode contains an empty string, return
+ * the number in national format without any carrier code.
+ *
+ * @param number the phone number to be formatted
+ * @param carrierCode the carrier selection code to be used
+ * @return the formatted phone number in national format for dialing using the carrier as
+ * specified in the carrierCode
+ */
public String formatNationalNumberWithCarrierCode(PhoneNumber number, String carrierCode) {
int countryCode = number.getCountryCode();
String nationalSignificantNumber = getNationalSignificantNumber(number);
@@ -851,6 +891,29 @@ public class PhoneNumberUtil {
}
/**
+ * Formats a phone number in national format for dialing using the carrier as specified in the
+ * preferred_domestic_carrier_code field of the PhoneNumber object passed in. If that is missing,
+ * use the fallbackCarrierCode passed in instead. If there is no preferred_domestic_carrier_code,
+ * and the fallbackCarrierCode contains an empty string, return the number in national format
+ * without any carrier code.
+ *
+ * Use formatNationalNumberWithCarrierCode instead if the carrier code passed in should take
+ * precedence over the number's preferred_domestic_carrier_code when formatting.
+ *
+ * @param number the phone number to be formatted
+ * @param fallbackCarrierCode the carrier selection code to be used, if none is found in the
+ * phone number itself
+ * @return the formatted phone number in national format for dialing using the number's
+ * preferred_domestic_carrier_code, or the fallbackCarrierCode passed in if none is found
+ */
+ public String formatNationalNumberWithPreferredCarrierCode(PhoneNumber number,
+ String fallbackCarrierCode) {
+ return formatNationalNumberWithCarrierCode(number, number.hasPreferredDomesticCarrierCode()
+ ? number.getPreferredDomesticCarrierCode()
+ : fallbackCarrierCode);
+ }
+
+ /**
* Formats a phone number for out-of-country dialing purpose. If no countryCallingFrom
* is supplied, we format the number in its INTERNATIONAL format. If the countryCallingFrom is
* the same as the country where the number is from, then NATIONAL formatting will be applied.
@@ -1027,7 +1090,7 @@ public class PhoneNumberUtil {
}
// Note that carrierCode is optional - if NULL or an empty string, no carrier code replacement
- // will take place. Carrier code replacement occurs before national prefix replacement.
+ // will take place.
private String formatAccordingToFormats(String nationalNumber,
List<NumberFormat> availableFormats,
PhoneNumberFormat numberFormat,
@@ -1038,9 +1101,10 @@ public class PhoneNumberUtil {
// We always use the last leading_digits_pattern, as it is the most detailed.
numFormat.getLeadingDigitsPattern(size - 1)).matcher(nationalNumber).lookingAt()) {
Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber);
- String numberFormatRule = numFormat.getFormat();
if (m.matches()) {
- if (carrierCode != null && carrierCode.length() > 0 &&
+ String numberFormatRule = numFormat.getFormat();
+ if (numberFormat == PhoneNumberFormat.NATIONAL &&
+ carrierCode != null && carrierCode.length() > 0 &&
numFormat.getDomesticCarrierCodeFormattingRule().length() > 0) {
// Replace the $CC in the formatting rule with the desired carrier code.
String carrierCodeFormattingRule = numFormat.getDomesticCarrierCodeFormattingRule();
@@ -1050,15 +1114,18 @@ public class PhoneNumberUtil {
// combined in the appropriate way.
numberFormatRule = FIRST_GROUP_PATTERN.matcher(numberFormatRule)
.replaceFirst(carrierCodeFormattingRule);
- }
- String nationalPrefixFormattingRule = numFormat.getNationalPrefixFormattingRule();
- if (numberFormat == PhoneNumberFormat.NATIONAL &&
- nationalPrefixFormattingRule != null &&
- nationalPrefixFormattingRule.length() > 0) {
- Matcher firstGroupMatcher = FIRST_GROUP_PATTERN.matcher(numberFormatRule);
- return m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule));
- } else {
return m.replaceAll(numberFormatRule);
+ } else {
+ // Use the national prefix formatting rule instead.
+ String nationalPrefixFormattingRule = numFormat.getNationalPrefixFormattingRule();
+ if (numberFormat == PhoneNumberFormat.NATIONAL &&
+ nationalPrefixFormattingRule != null &&
+ nationalPrefixFormattingRule.length() > 0) {
+ Matcher firstGroupMatcher = FIRST_GROUP_PATTERN.matcher(numberFormatRule);
+ return m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule));
+ } else {
+ return m.replaceAll(numberFormatRule);
+ }
}
}
}
@@ -1565,15 +1632,15 @@ public class PhoneNumberUtil {
* @param nationalNumber a string buffer to store the national significant number in, in the case
* that a country code was extracted. The number is appended to any existing contents. If no
* country code was extracted, this will be left unchanged.
- * @param storeCountryCodeSource true if the country_code_source field of phoneNumber should be
- * populated.
+ * @param keepRawInput true if the country_code_source and preferred_carrier_code fields of
+ * phoneNumber should be populated.
* @param phoneNumber the PhoneNumber object that needs to be populated with country code and
* country code source. Note the country code is always populated, whereas country code source
* is only populated when keepCountryCodeSource is true.
* @return the country code extracted or 0 if none could be extracted
*/
int maybeExtractCountryCode(String number, PhoneMetadata defaultRegionMetadata,
- StringBuffer nationalNumber, boolean storeCountryCodeSource,
+ StringBuffer nationalNumber, boolean keepRawInput,
PhoneNumber phoneNumber)
throws NumberParseException {
if (number.length() == 0) {
@@ -1588,7 +1655,7 @@ public class PhoneNumberUtil {
CountryCodeSource countryCodeSource =
maybeStripInternationalPrefixAndNormalize(fullNumber, possibleCountryIddPrefix);
- if (storeCountryCodeSource) {
+ if (keepRawInput) {
phoneNumber.setCountryCodeSource(countryCodeSource);
}
if (countryCodeSource != CountryCodeSource.FROM_DEFAULT_COUNTRY) {
@@ -1621,11 +1688,7 @@ public class PhoneNumberUtil {
// If so, strip this, and see if the resultant number is valid.
StringBuffer potentialNationalNumber =
new StringBuffer(normalizedNumber.substring(defaultCountryCodeString.length()));
- maybeStripNationalPrefix(
- potentialNationalNumber,
- defaultRegionMetadata.getNationalPrefixForParsing(),
- defaultRegionMetadata.getNationalPrefixTransformRule(),
- validNumberPattern);
+ maybeStripNationalPrefixAndCarrierCode(potentialNationalNumber, defaultRegionMetadata);
Matcher possibleNumberMatcher =
regexCache.getPatternForRegex(generalDesc.getPossibleNumberPattern()).matcher(
potentialNationalNumber);
@@ -1635,7 +1698,7 @@ public class PhoneNumberUtil {
(possibleNumberMatcher.lookingAt() &&
possibleNumberMatcher.end() != potentialNationalNumber.length())) {
nationalNumber.append(potentialNationalNumber);
- if (storeCountryCodeSource) {
+ if (keepRawInput) {
phoneNumber.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
}
phoneNumber.setCountryCode(defaultCountryCode);
@@ -1718,45 +1781,54 @@ public class PhoneNumberUtil {
*
* @param number the normalized telephone number that we wish to strip any national
* dialing prefix from
- * @param possibleNationalPrefix a regex that represents the national direct dialing prefix
- * from the country we think this number may be dialed in
- * @param transformRule the string that specifies how number should be transformed according
- * to the regex specified in possibleNationalPrefix
- * @param nationalNumberRule a regular expression that specifies what a valid phonenumber from
- * this region should look like after any national prefix was stripped or transformed
+ * @param metadata the metadata for the country that we think this number is from
+ * @return the carrier code extracted if it is present, otherwise return an empty string.
*/
- void maybeStripNationalPrefix(StringBuffer number, String possibleNationalPrefix,
- String transformRule, Pattern nationalNumberRule) {
+ String maybeStripNationalPrefixAndCarrierCode(StringBuffer number, PhoneMetadata metadata) {
+ String carrierCode = "";
int numberLength = number.length();
+ String possibleNationalPrefix = metadata.getNationalPrefixForParsing();
if (numberLength == 0 || possibleNationalPrefix.length() == 0) {
// Early return for numbers of zero length.
- return;
+ return carrierCode;
}
// Attempt to parse the first digits as a national prefix.
- Matcher m = regexCache.getPatternForRegex(possibleNationalPrefix).matcher(number);
- if (m.lookingAt()) {
- // m.group(1) == null implies nothing was captured by the capturing groups in
- // possibleNationalPrefix; therefore, no transformation is necessary, and we
- // just remove the national prefix.
- if (transformRule == null || transformRule.length() == 0 || m.group(1) == null) {
+ Matcher prefixMatcher = regexCache.getPatternForRegex(possibleNationalPrefix).matcher(number);
+ if (prefixMatcher.lookingAt()) {
+ Pattern nationalNumberRule =
+ regexCache.getPatternForRegex(metadata.getGeneralDesc().getNationalNumberPattern());
+ // prefixMatcher.group(numOfGroups) == null implies nothing was captured by the capturing
+ // groups in possibleNationalPrefix; therefore, no transformation is necessary, and we just
+ // remove the national prefix.
+ int numOfGroups = prefixMatcher.groupCount();
+ String transformRule = metadata.getNationalPrefixTransformRule();
+ if (transformRule == null || transformRule.length() == 0 ||
+ prefixMatcher.group(numOfGroups) == null) {
// Check that the resultant number is viable. If not, return.
- Matcher nationalNumber = nationalNumberRule.matcher(number.substring(m.end()));
+ Matcher nationalNumber = nationalNumberRule.matcher(number.substring(prefixMatcher.end()));
if (!nationalNumber.matches()) {
- return;
+ return carrierCode;
+ }
+ if (numOfGroups > 0 && prefixMatcher.group(numOfGroups) != null) {
+ carrierCode = prefixMatcher.group(1);
}
- number.delete(0, m.end());
+ number.delete(0, prefixMatcher.end());
} else {
// Check that the resultant number is viable. If not, return. Check this by copying the
// string buffer and making the transformation on the copy first.
StringBuffer transformedNumber = new StringBuffer(number);
- transformedNumber.replace(0, numberLength, m.replaceFirst(transformRule));
+ transformedNumber.replace(0, numberLength, prefixMatcher.replaceFirst(transformRule));
Matcher nationalNumber = nationalNumberRule.matcher(transformedNumber.toString());
if (!nationalNumber.matches()) {
- return;
+ return carrierCode;
+ }
+ if (numOfGroups > 1) {
+ carrierCode = prefixMatcher.group(1);
}
number.replace(0, number.length(), transformedNumber.toString());
}
}
+ return carrierCode;
}
/**
@@ -1842,11 +1914,11 @@ public class PhoneNumberUtil {
*
* @param numberToParse number that we are attempting to parse. This can contain formatting
* such as +, ( and -, as well as a phone number extension.
- * @param defaultCountry the ISO 3166-1 two-letter country code that denotes the
- * country that we are expecting the number to be from. This is only used
- * if the number being parsed is not written in international format.
- * The country code for the number in this case would be stored as that
- * of the default country supplied.
+ * @param defaultCountry the ISO 3166-1 two-letter country code that denotes the country that
+ * we are expecting the number to be from. This is only used if the
+ * number being parsed is not written in international format. The
+ * country code for the number in this case would be stored as that of
+ * the default country supplied.
* @return a phone number proto buffer filled with the parsed number
* @throws NumberParseException if the string is not considered to be a viable phone number or if
* no default country was supplied
@@ -1867,6 +1939,50 @@ public class PhoneNumberUtil {
}
/**
+ * Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}. This
+ * is a shortcut for {@link #findNumbers(CharSequence, String, Leniency, long)
+ * getMatcher(text, defaultCountry, Leniency.VALID, Long.MAX_VALUE)}.
+ *
+ * @param text the text to search for phone numbers, null for no text
+ * @param defaultCountry the ISO 3166-1 two-letter country code that denotes the country that
+ * we are expecting the number to be from. This is only used if the
+ * number being parsed is not written in international format. The
+ * country code for the number in this case would be stored as that of
+ * the default country supplied. May be null if only international
+ * numbers are expected.
+ */
+ public Iterable<PhoneNumberMatch> findNumbers(CharSequence text, String defaultCountry) {
+ return findNumbers(text, defaultCountry, Leniency.VALID, Long.MAX_VALUE);
+ }
+
+ /**
+ * Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}.
+ *
+ * @param text the text to search for phone numbers, null for no text
+ * @param defaultCountry the ISO 3166-1 two-letter country code that denotes the country that
+ * we are expecting the number to be from. This is only used if the
+ * number being parsed is not written in international format. The
+ * country code for the number in this case would be stored as that of
+ * the default country supplied. May be null if only international
+ * numbers are expected.
+ * @param leniency the leniency to use when evaluating candidate phone numbers
+ * @param maxTries the maximum number of invalid numbers to try before giving up on the
+ * text. This is to cover degenerate cases where the text has a lot of
+ * false positives in it. Must be {@code >= 0}.
+ */
+ public Iterable<PhoneNumberMatch> findNumbers(
+ final CharSequence text, final String defaultCountry, final Leniency leniency,
+ final long maxTries) {
+
+ return new Iterable<PhoneNumberMatch>() {
+ public Iterator<PhoneNumberMatch> iterator() {
+ return new PhoneNumberMatcher(
+ PhoneNumberUtil.this, text, defaultCountry, leniency, maxTries);
+ }
+ };
+ }
+
+ /**
* Parses a string and fills up the phoneNumber. This method is the same as the public
* parse() method, with the exception that it allows the default country to be null, for use by
* isNumberMatch(). checkRegion should be set to false if it is permitted for the default country
@@ -1933,13 +2049,11 @@ public class PhoneNumberUtil {
"The string supplied is too short to be a phone number.");
}
if (countryMetadata != null) {
- Pattern validNumberPattern =
- regexCache.getPatternForRegex(countryMetadata.getGeneralDesc()
- .getNationalNumberPattern());
- maybeStripNationalPrefix(normalizedNationalNumber,
- countryMetadata.getNationalPrefixForParsing(),
- countryMetadata.getNationalPrefixTransformRule(),
- validNumberPattern);
+ String carrierCode =
+ maybeStripNationalPrefixAndCarrierCode(normalizedNationalNumber, countryMetadata);
+ if (keepRawInput) {
+ phoneNumber.setPreferredDomesticCarrierCode(carrierCode);
+ }
}
int lengthOfNationalNumber = normalizedNationalNumber.length();
if (lengthOfNationalNumber < MIN_LENGTH_FOR_NSN) {
@@ -1983,12 +2097,14 @@ public class PhoneNumberUtil {
firstNumber.mergeFrom(firstNumberIn);
PhoneNumber secondNumber = new PhoneNumber();
secondNumber.mergeFrom(secondNumberIn);
- // First clear raw_input and country_code_source field and any empty-string extensions so that
- // we can use the PhoneNumber.exactlySameAs() method.
+ // First clear raw_input, country_code_source and preferred_domestic_carrier_code fields and any
+ // empty-string extensions so that we can use the proto-buffer equality method.
firstNumber.clearRawInput();
firstNumber.clearCountryCodeSource();
+ firstNumber.clearPreferredDomesticCarrierCode();
secondNumber.clearRawInput();
secondNumber.clearCountryCodeSource();
+ secondNumber.clearPreferredDomesticCarrierCode();
if (firstNumber.hasExtension() &&
firstNumber.getExtension().length() == 0) {
firstNumber.clearExtension();
diff --git a/java/src/com/google/i18n/phonenumbers/Phonenumber.java b/java/src/com/google/i18n/phonenumbers/Phonenumber.java
index 608a3b40..89382a1f 100644
--- a/java/src/com/google/i18n/phonenumbers/Phonenumber.java
+++ b/java/src/com/google/i18n/phonenumbers/Phonenumber.java
@@ -15,7 +15,7 @@
*/
/**
- * Definition of the class representing international telephone numbers. This class is hand created
+ * Definition of the class representing international telephone numbers. This class is hand-created
* based on the class file compiled from phonenumber.proto. Please refer to that file for detailed
* descriptions of the meaning of each field.
*/
@@ -141,6 +141,25 @@ public final class Phonenumber {
return this;
}
+ // optional string preferred_domestic_carrier_code = 7;
+ private boolean hasPreferredDomesticCarrierCode;
+ private java.lang.String preferredDomesticCarrierCode_ = "";
+ public boolean hasPreferredDomesticCarrierCode() { return hasPreferredDomesticCarrierCode; }
+ public String getPreferredDomesticCarrierCode() { return preferredDomesticCarrierCode_; }
+ public PhoneNumber setPreferredDomesticCarrierCode(String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ hasPreferredDomesticCarrierCode = true;
+ preferredDomesticCarrierCode_ = value;
+ return this;
+ }
+ public PhoneNumber clearPreferredDomesticCarrierCode() {
+ hasPreferredDomesticCarrierCode = false;
+ preferredDomesticCarrierCode_ = "";
+ return this;
+ }
+
public final PhoneNumber clear() {
clearCountryCode();
clearNationalNumber();
@@ -148,6 +167,7 @@ public final class Phonenumber {
clearItalianLeadingZero();
clearRawInput();
clearCountryCodeSource();
+ clearPreferredDomesticCarrierCode();
return this;
}
@@ -170,6 +190,9 @@ public final class Phonenumber {
if (other.hasCountryCodeSource()) {
setCountryCodeSource(other.getCountryCodeSource());
}
+ if (other.hasPreferredDomesticCarrierCode()) {
+ setPreferredDomesticCarrierCode(other.getPreferredDomesticCarrierCode());
+ }
return this;
}
@@ -182,7 +205,9 @@ public final class Phonenumber {
}
return (countryCode_ == other.countryCode_ && nationalNumber_ == other.nationalNumber_ &&
extension_.equals(other.extension_) && italianLeadingZero_ == other.italianLeadingZero_ &&
- rawInput_.equals(other.rawInput_) && countryCodeSource_ == other.countryCodeSource_);
+ rawInput_.equals(other.rawInput_) && countryCodeSource_ == other.countryCodeSource_ &&
+ preferredDomesticCarrierCode_.equals(other.preferredDomesticCarrierCode_) &&
+ hasPreferredDomesticCarrierCode() == other.hasPreferredDomesticCarrierCode());
}
@Override
@@ -195,7 +220,7 @@ public final class Phonenumber {
// Simplified rendition of the hashCode function automatically generated from the proto
// compiler with java_generate_equals_and_hash set to true. We are happy with unset values to
// be considered equal to their explicitly-set equivalents, so don't check if any value is
- // unknown.
+ // unknown. The only exception to this is the preferred domestic carrier code.
int hash = 41;
hash = (53 * hash) + getCountryCode();
hash = (53 * hash) + Long.valueOf(getNationalNumber()).hashCode();
@@ -203,6 +228,8 @@ public final class Phonenumber {
hash = (53 * hash) + (getItalianLeadingZero() ? 1231 : 1237);
hash = (53 * hash) + getRawInput().hashCode();
hash = (53 * hash) + getCountryCodeSource().hashCode();
+ hash = (53 * hash) + getPreferredDomesticCarrierCode().hashCode();
+ hash = (53 * hash) + (hasPreferredDomesticCarrierCode() ? 1231 : 1237);
return hash;
}
@@ -220,6 +247,10 @@ public final class Phonenumber {
if (hasCountryCodeSource()) {
outputString.append(" Country Code Source: ").append(countryCodeSource_);
}
+ if (hasPreferredDomesticCarrierCode()) {
+ outputString.append(" Preferred Domestic Carrier Code: ").
+ append(preferredDomesticCarrierCode_);
+ }
return outputString.toString();
}
}
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AC b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AC
new file mode 100644
index 00000000..5bf42890
--- /dev/null
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AC
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF
index 1fc75cc6..cd1431f1 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO
index 191b55c7..0395299f 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR
index 7fc1610f..67fe311d 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL
index e6bb05ed..2e9c0d8d 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO
index 84926a14..e89645ad 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR
index 1b3a91c7..979fa17c 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK
index 84b40d6e..2b9a712c 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO
index f75752f4..2d2ff182 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE
index fd894c53..22f3da28 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR
index 641ce7fc..e66f1579 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW
index 3d5cd85f..7ab6e363 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA
index e0c1ec1c..984aeba2 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU
index e3b025ff..1b313744 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU
index 782c700f..a65c8e32 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC
index d8528060..3d74da04 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH
index 96e6c73e..c52c527e 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR
index 595e26cd..0d20cbb5 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR
Binary files differ
diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE
index 3cc77d15..96b653fc 100644
--- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE
+++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE
Binary files differ