/** * Formats a phone number for out-of-country dialing purposes. * * Note that in this version, if the number was entered originally using alpha characters and * this version of the number is stored in raw_input, this representation of the number will be * used rather than the digit representation. Grouping information, as specified by characters * such as "-" and " ", will be retained. * * <p><b>Caveats:</b></p> * <ul> * <li> This will not produce good results if the country calling code is both present in the raw * input _and_ is the start of the national number. This is not a problem in the regions * which typically use alpha numbers. * <li> This will also not produce good results if the raw input has any grouping information * within the first three digits of the national number, and if the function needs to strip * preceding digits/words in the raw input before these digits. Normally people group the * first three digits together so this is not a huge problem - and will be fixed if it * proves to be so. * </ul> * * @param PhoneNumber $number the phone number that needs to be formatted * @param String $regionCallingFrom the region where the call is being placed * @return String the formatted phone number */ public function formatOutOfCountryKeepingAlphaChars(PhoneNumber $number, $regionCallingFrom) { $rawInput = $number->getRawInput(); // If there is no raw input, then we can't keep alpha characters because there aren't any. // In this case, we return formatOutOfCountryCallingNumber. if (mb_strlen($rawInput) == 0) { return $this->formatOutOfCountryCallingNumber($number, $regionCallingFrom); } $countryCode = $number->getCountryCode(); if (!$this->hasValidCountryCallingCode($countryCode)) { return $rawInput; } // Strip any prefix such as country calling code, IDD, that was present. We do this by comparing // the number in raw_input with the parsed number. // To do this, first we normalize punctuation. We retain number grouping symbols such as " " // only. $rawInput = $this->normalizeHelper($rawInput, self::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS, true); // Now we trim everything before the first three digits in the parsed number. We choose three // because all valid alpha numbers have 3 digits at the start - if it does not, then we don't // trim anything at all. Similarly, if the national number was less than three digits, we don't // trim anything at all. $nationalNumber = $this->getNationalSignificantNumber($number); if (mb_strlen($nationalNumber) > 3) { $firstNationalNumberDigit = strpos($rawInput, substr($nationalNumber, 0, 3)); if ($firstNationalNumberDigit !== false) { $rawInput = substr($rawInput, $firstNationalNumberDigit); } } $metadataForRegionCallingFrom = $this->getMetadataForRegion($regionCallingFrom); if ($countryCode == self::NANPA_COUNTRY_CODE) { if ($this->isNANPACountry($regionCallingFrom)) { return $countryCode . " " . $rawInput; } } else { if ($metadataForRegionCallingFrom !== null && $countryCode == $this->getCountryCodeForValidRegion($regionCallingFrom)) { $formattingPattern = $this->chooseFormattingPatternForNumber($metadataForRegionCallingFrom->numberFormats(), $nationalNumber); if ($formattingPattern === null) { // If no pattern above is matched, we format the original input. return $rawInput; } $newFormat = new NumberFormat(); $newFormat->mergeFrom($formattingPattern); // The first group is the first group of digits that the user wrote together. $newFormat->setPattern("(\\d+)(.*)"); // Here we just concatenate them back together after the national prefix has been fixed. $newFormat->setFormat("\$1\$2"); // Now we format using this pattern instead of the default pattern, but with the national // prefix prefixed if necessary. // This will not work in the cases where the pattern (and not the leading digits) decide // whether a national prefix needs to be used, since we have overridden the pattern to match // anything, but that is not the case in the metadata to date. return $this->formatNsnUsingPattern($rawInput, $newFormat, PhoneNumberFormat::NATIONAL); } } $internationalPrefixForFormatting = ""; // If an unsupported region-calling-from is entered, or a country with multiple international // prefixes, the international format of the number is returned, unless there is a preferred // international prefix. if ($metadataForRegionCallingFrom !== null) { $internationalPrefix = $metadataForRegionCallingFrom->getInternationalPrefix(); $uniqueInternationalPrefixMatcher = new Matcher(self::UNIQUE_INTERNATIONAL_PREFIX, $internationalPrefix); $internationalPrefixForFormatting = $uniqueInternationalPrefixMatcher->matches() ? $internationalPrefix : $metadataForRegionCallingFrom->getPreferredInternationalPrefix(); } $formattedNumber = $rawInput; $regionCode = $this->getRegionCodeForCountryCode($countryCode); // Metadata cannot be null because the country calling code is valid. $metadataForRegion = $this->getMetadataForRegionOrCallingCode($countryCode, $regionCode); $this->maybeAppendFormattedExtension($number, $metadataForRegion, PhoneNumberFormat::INTERNATIONAL, $formattedNumber); if (mb_strlen($internationalPrefixForFormatting) > 0) { $formattedNumber = $internationalPrefixForFormatting . " " . $countryCode . " " . $formattedNumber; } else { // Invalid region entered as country-calling-from (so no metadata was found for it) or the // region chosen has multiple international dialling prefixes. $this->prefixNumberWithCountryCallingCode($countryCode, PhoneNumberFormat::INTERNATIONAL, $formattedNumber); } return $formattedNumber; }
public function testFormatByPattern() { $newNumFormat = new NumberFormat(); $newNumFormat->setPattern("(\\d{3})(\\d{3})(\\d{4})"); $newNumFormat->setFormat("(\$1) \$2-\$3"); $newNumberFormats = array(); $newNumberFormats[] = $newNumFormat; $this->assertEquals("(650) 253-0000", $this->phoneUtil->formatByPattern(self::$usNumber, PhoneNumberFormat::NATIONAL, $newNumberFormats)); $this->assertEquals("+1 (650) 253-0000", $this->phoneUtil->formatByPattern(self::$usNumber, PhoneNumberFormat::INTERNATIONAL, $newNumberFormats)); $this->assertEquals("+1-650-253-0000", $this->phoneUtil->formatByPattern(self::$usNumber, PhoneNumberFormat::RFC3966, $newNumberFormats)); // $NP is set to '1' for the US. Here we check that for other NANPA countries the US rules are // followed. $newNumFormat->setNationalPrefixFormattingRule('$NP ($FG)'); $newNumFormat->setFormat("\$1 \$2-\$3"); $this->assertEquals("1 (242) 365-1234", $this->phoneUtil->formatByPattern(self::$bsNumber, PhoneNumberFormat::NATIONAL, $newNumberFormats)); $this->assertEquals("+1 242 365-1234", $this->phoneUtil->formatByPattern(self::$bsNumber, PhoneNumberFormat::INTERNATIONAL, $newNumberFormats)); $newNumFormat->setPattern("(\\d{2})(\\d{5})(\\d{3})"); $newNumFormat->setFormat("\$1-\$2 \$3"); $newNumberFormats[0] = $newNumFormat; $this->assertEquals("02-36618 300", $this->phoneUtil->formatByPattern(self::$itNumber, PhoneNumberFormat::NATIONAL, $newNumberFormats)); $this->assertEquals("+39 02-36618 300", $this->phoneUtil->formatByPattern(self::$itNumber, PhoneNumberFormat::INTERNATIONAL, $newNumberFormats)); $newNumFormat->setNationalPrefixFormattingRule('$NP$FG'); $newNumFormat->setPattern("(\\d{2})(\\d{4})(\\d{4})"); $newNumFormat->setFormat("\$1 \$2 \$3"); $newNumberFormats[0] = $newNumFormat; $this->assertEquals("020 7031 3000", $this->phoneUtil->formatByPattern(self::$gbNumber, PhoneNumberFormat::NATIONAL, $newNumberFormats)); $newNumFormat->setNationalPrefixFormattingRule('($NP$FG)'); $this->assertEquals("(020) 7031 3000", $this->phoneUtil->formatByPattern(self::$gbNumber, PhoneNumberFormat::NATIONAL, $newNumberFormats)); $newNumFormat->setNationalPrefixFormattingRule(""); $this->assertEquals("20 7031 3000", $this->phoneUtil->formatByPattern(self::$gbNumber, PhoneNumberFormat::NATIONAL, $newNumberFormats)); $this->assertEquals("+44 20 7031 3000", $this->phoneUtil->formatByPattern(self::$gbNumber, PhoneNumberFormat::INTERNATIONAL, $newNumberFormats)); }