diff options
author | Shaopeng Jia <shaopengjia@google.com> | 2011-03-22 14:22:53 +0100 |
---|---|---|
committer | Shaopeng Jia <shaopengjia@google.com> | 2011-03-22 14:56:26 +0100 |
commit | 52699e08e855fb0957944b4e73358ad9e0007c0c (patch) | |
tree | 54d545415d88dca116dbe3ad15e8efca97688904 /java/src/com | |
parent | b93a7356a018d48143ad7e6adfe9544dc4b89d19 (diff) | |
download | libphonenumber-52699e08e855fb0957944b4e73358ad9e0007c0c.tar.gz |
Refresh external/libphonenumber to r136.
Change-Id: I5a44a2d15071d319a273a078ff85c25877b174c0
Diffstat (limited to 'java/src/com')
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 Binary files differnew file mode 100644 index 00000000..5bf42890 --- /dev/null +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AC diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF Binary files differindex 1fc75cc6..cd1431f1 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO Binary files differindex 191b55c7..0395299f 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BO diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR Binary files differindex 7fc1610f..67fe311d 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL Binary files differindex e6bb05ed..2e9c0d8d 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CL diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO Binary files differindex 84926a14..e89645ad 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR Binary files differindex 1b3a91c7..979fa17c 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK Binary files differindex 84b40d6e..2b9a712c 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DK diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO Binary files differindex f75752f4..2d2ff182 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FO diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE Binary files differindex fd894c53..22f3da28 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_GE diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR Binary files differindex 641ce7fc..e66f1579 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KR diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW Binary files differindex 3d5cd85f..7ab6e363 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_KW diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA Binary files differindex e0c1ec1c..984aeba2 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LA diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU Binary files differindex e3b025ff..1b313744 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LU diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU Binary files differindex 782c700f..a65c8e32 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC Binary files differindex d8528060..3d74da04 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH Binary files differindex 96e6c73e..c52c527e 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SH diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR Binary files differindex 595e26cd..0d20cbb5 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TR diff --git a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE Binary files differindex 3cc77d15..96b653fc 100644 --- a/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE +++ b/java/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VE |