func normalizeDiallableCharsOnly(number string) string {
	return normalizeHelper(
		number, DIALLABLE_CHAR_MAPPINGS, true  )
}
Normalizes a string of characters representing a phone number. This
strips all characters which are not diallable on a mobile phone
keypad (including all non-ASCII digits).
package phonenumbers
import (
	"errors"
	fmt "fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"unicode"
	"github.com/golang/protobuf/proto"
	"golang.org/x/text/language"
	"golang.org/x/text/language/display"
)
const (
	MIN_LENGTH_FOR_NSN = 2
	MAX_LENGTH_FOR_NSN = 17
	MAX_LENGTH_COUNTRY_CODE = 3
	MAX_INPUT_STRING_LENGTH = 250
	UNKNOWN_REGION = "ZZ"
	NANPA_COUNTRY_CODE = 1
	COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX = "3"
	PLUS_SIGN = '+'
	STAR_SIGN = '*'
	RFC3966_EXTN_PREFIX     = ";ext="
	RFC3966_PREFIX          = "tel:"
	RFC3966_PHONE_CONTEXT   = ";phone-context="
	RFC3966_ISDN_SUBADDRESS = ";isub="
	VALID_PUNCTUATION = "-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F " +
		"\u00A0\u00AD\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D." +
		"\\[\\]/~\u2053\u223C\uFF5E"
	DIGITS = "\\p{Nd}"
	VALID_ALPHA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	PLUS_CHARS  = "+\uFF0B"
	UNKNOWN_TIMEZONE = "Etc/Unknown"
)
var (
	MOBILE_TOKEN_MAPPINGS = map[int]string{
		52: "1",
		54: "9",
	}
	DIALLABLE_CHAR_MAPPINGS = map[rune]rune{
		'1':       '1',
		'2':       '2',
		'3':       '3',
		'4':       '4',
		'5':       '5',
		'6':       '6',
		'7':       '7',
		'8':       '8',
		'9':       '9',
		'0':       '0',
		PLUS_SIGN: PLUS_SIGN,
		'*':       '*',
	}
	ALPHA_MAPPINGS = map[rune]rune{
		'A': '2',
		'B': '2',
		'C': '2',
		'D': '3',
		'E': '3',
		'F': '3',
		'G': '4',
		'H': '4',
		'I': '4',
		'J': '5',
		'K': '5',
		'L': '5',
		'M': '6',
		'N': '6',
		'O': '6',
		'P': '7',
		'Q': '7',
		'R': '7',
		'S': '7',
		'T': '8',
		'U': '8',
		'V': '8',
		'W': '9',
		'X': '9',
		'Y': '9',
		'Z': '9',
	}
	ALPHA_PHONE_MAPPINGS = map[rune]rune{
		'1':       '1',
		'2':       '2',
		'3':       '3',
		'4':       '4',
		'5':       '5',
		'6':       '6',
		'7':       '7',
		'8':       '8',
		'9':       '9',
		'0':       '0',
		PLUS_SIGN: PLUS_SIGN,
		'*':       '*',
		'A':       '2',
		'B':       '2',
		'C':       '2',
		'D':       '3',
		'E':       '3',
		'F':       '3',
		'G':       '4',
		'H':       '4',
		'I':       '4',
		'J':       '5',
		'K':       '5',
		'L':       '5',
		'M':       '6',
		'N':       '6',
		'O':       '6',
		'P':       '7',
		'Q':       '7',
		'R':       '7',
		'S':       '7',
		'T':       '8',
		'U':       '8',
		'V':       '8',
		'W':       '9',
		'X':       '9',
		'Y':       '9',
		'Z':       '9',
	}
	ALL_PLUS_NUMBER_GROUPING_SYMBOLS = map[rune]rune{
		'1':       '1',
		'2':       '2',
		'3':       '3',
		'4':       '4',
		'5':       '5',
		'6':       '6',
		'7':       '7',
		'8':       '8',
		'9':       '9',
		'0':       '0',
		PLUS_SIGN: PLUS_SIGN,
		'*':       '*',
		'A':       'A',
		'B':       'B',
		'C':       'C',
		'D':       'D',
		'E':       'E',
		'F':       'F',
		'G':       'G',
		'H':       'H',
		'I':       'I',
		'J':       'J',
		'K':       'K',
		'L':       'L',
		'M':       'M',
		'N':       'N',
		'O':       'O',
		'P':       'P',
		'Q':       'Q',
		'R':       'R',
		'S':       'S',
		'T':       'T',
		'U':       'U',
		'V':       'V',
		'W':       'W',
		'X':       'X',
		'Y':       'Y',
		'Z':       'Z',
		'a':       'A',
		'b':       'B',
		'c':       'C',
		'd':       'D',
		'e':       'E',
		'f':       'F',
		'g':       'G',
		'h':       'H',
		'i':       'I',
		'j':       'J',
		'k':       'K',
		'l':       'L',
		'm':       'M',
		'n':       'N',
		'o':       'O',
		'p':       'P',
		'q':       'Q',
		'r':       'R',
		's':       'S',
		't':       'T',
		'u':       'U',
		'v':       'V',
		'w':       'W',
		'x':       'X',
		'y':       'Y',
		'z':       'Z',
		'-':       '-',
		'\uFF0D':  '-',
		'\u2010':  '-',
		'\u2011':  '-',
		'\u2012':  '-',
		'\u2013':  '-',
		'\u2014':  '-',
		'\u2015':  '-',
		'\u2212':  '-',
		'/':       '/',
		'\uFF0F':  '/',
		' ':       ' ',
		'\u3000':  ' ',
		'\u2060':  ' ',
		'.':       '.',
		'\uFF0E':  '.',
	}
	UNIQUE_INTERNATIONAL_PREFIX = regexp.MustCompile("[\\d]+(?:[~\u2053\u223C\uFF5E][\\d]+)?")
	PLUS_CHARS_PATTERN      = regexp.MustCompile("[" + PLUS_CHARS + "]+")
	SEPARATOR_PATTERN       = regexp.MustCompile("[" + VALID_PUNCTUATION + "]+")
	NOT_SEPARATOR_PATTERN   = regexp.MustCompile("[^" + VALID_PUNCTUATION + "]+")
	CAPTURING_DIGIT_PATTERN = regexp.MustCompile("(" + DIGITS + ")")
	VALID_START_CHAR         = "[" + PLUS_CHARS + DIGITS + "]"
	VALID_START_CHAR_PATTERN = regexp.MustCompile(VALID_START_CHAR)
	SECOND_NUMBER_START         = "[\\\\/] *x"
	SECOND_NUMBER_START_PATTERN = regexp.MustCompile(SECOND_NUMBER_START)
	UNWANTED_END_CHARS        = "[[\\P{N}&&\\P{L}]&&[^#]]+$"
	UNWANTED_END_CHAR_PATTERN = regexp.MustCompile(UNWANTED_END_CHARS)
	VALID_ALPHA_PHONE_PATTERN = regexp.MustCompile("^(?:.*?[A-Za-z]){3}.*$")
	VALID_PHONE_NUMBER = DIGITS + "{" + strconv.Itoa(MIN_LENGTH_FOR_NSN) + "}" + "|" +
		"[" + PLUS_CHARS + "]*(?:[" + VALID_PUNCTUATION + string(STAR_SIGN) +
		"]*" + DIGITS + "){3,}[" +
		VALID_PUNCTUATION + string(STAR_SIGN) + VALID_ALPHA + DIGITS + "]*"
	DEFAULT_EXTN_PREFIX = " ext. "
	CAPTURING_EXTN_DIGITS = "(" + DIGITS + "{1,7})"
	EXTN_PATTERNS_FOR_PARSING = RFC3966_EXTN_PREFIX + CAPTURING_EXTN_DIGITS + "|" + "[ \u00A0\\t,]*" +
		"(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|" +
		"[;,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)" +
		"[:\\.\uFF0E]?[ \u00A0\\t,-]*" + CAPTURING_EXTN_DIGITS + "#?|" +
		"[- ]+(" + DIGITS + "{1,5})#"
	EXTN_PATTERNS_FOR_MATCHING = RFC3966_EXTN_PREFIX + CAPTURING_EXTN_DIGITS + "|" + "[ \u00A0\\t,]*" +
		"(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|" +
		"[x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)" +
		"[:\\.\uFF0E]?[ \u00A0\\t,-]*" + CAPTURING_EXTN_DIGITS + "#?|" +
		"[- ]+(" + DIGITS + "{1,5})#"
	EXTN_PATTERN = regexp.MustCompile("(?:" + EXTN_PATTERNS_FOR_PARSING + ")$")
	VALID_PHONE_NUMBER_PATTERN = regexp.MustCompile(
		"^(" + VALID_PHONE_NUMBER + "(?:" + EXTN_PATTERNS_FOR_PARSING + ")?)$")
	NON_DIGITS_PATTERN = regexp.MustCompile(`(\D+)`)
	DIGITS_PATTERN     = regexp.MustCompile(`(\d+)`)
	FIRST_GROUP_PATTERN = regexp.MustCompile(`(\$\d)`)
	NP_PATTERN          = regexp.MustCompile(`\$NP`)
	FG_PATTERN          = regexp.MustCompile(`\$FG`)
	CC_PATTERN          = regexp.MustCompile(`\$CC`)
	FIRST_GROUP_ONLY_PREFIX_PATTERN = regexp.MustCompile(`\(?\$1\)?`)
	REGION_CODE_FOR_NON_GEO_ENTITY = "001"
)
type PhoneNumberFormat int
const (
	E164 PhoneNumberFormat = iota
	INTERNATIONAL
	NATIONAL
	RFC3966
)
type PhoneNumberType int
const (
	FIXED_LINE PhoneNumberType = iota
	MOBILE
	FIXED_LINE_OR_MOBILE
	TOLL_FREE
	PREMIUM_RATE
	SHARED_COST
	VOIP
	PERSONAL_NUMBER
	PAGER
	UAN
	VOICEMAIL
	UNKNOWN
)
type MatchType int
const (
	NOT_A_NUMBER MatchType = iota
	NO_MATCH
	SHORT_NSN_MATCH
	NSN_MATCH
	EXACT_MATCH
)
type ValidationResult int
const (
	IS_POSSIBLE ValidationResult = iota
	INVALID_COUNTRY_CODE
	TOO_SHORT
	TOO_LONG
	IS_POSSIBLE_LOCAL_ONLY
	INVALID_LENGTH
)
type Leniency int
const (
	POSSIBLE Leniency = iota
	VALID
	STRICT_GROUPING
	EXACT_GROUPING
)
func (l Leniency) Verify(number *PhoneNumber, candidate string) bool {
	switch l {
	case POSSIBLE:
		return IsPossibleNumber(number)
	case VALID:
		if !IsValidNumber(number) ||
			!ContainsOnlyValidXChars(number, candidate) {
			return false
		}
		return IsNationalPrefixPresentIfRequired(number)
	case STRICT_GROUPING:
		if !IsValidNumber(number) ||
			!ContainsOnlyValidXChars(number, candidate) ||
			ContainsMoreThanOneSlashInNationalNumber(number, candidate) ||
			!IsNationalPrefixPresentIfRequired(number) {
			return false
		}
		return CheckNumberGroupingIsValid(number, candidate,
			func(number *PhoneNumber,
				normalizedCandidate string,
				expectedNumberGroups []string) bool {
				return AllNumberGroupsRemainGrouped(
					number, normalizedCandidate, expectedNumberGroups)
			})
	case EXACT_GROUPING:
		if !IsValidNumber(number) ||
			!ContainsOnlyValidXChars(number, candidate) ||
			ContainsMoreThanOneSlashInNationalNumber(number, candidate) ||
			!IsNationalPrefixPresentIfRequired(number) {
			return false
		}
		return CheckNumberGroupingIsValid(number, candidate,
			func(number *PhoneNumber,
				normalizedCandidate string,
				expectedNumberGroups []string) bool {
				return AllNumberGroupsAreExactlyPresent(
					number, normalizedCandidate, expectedNumberGroups)
			})
	}
	return false
}
var (
	nanpaRegions = make(map[string]struct{})
	regionToMetadataMap = make(map[string]*PhoneMetadata)
	countryCodeToNonGeographicalMetadataMap = make(map[int]*PhoneMetadata)
	regexCache    = make(map[string]*regexp.Regexp)
	regCacheMutex sync.RWMutex
	supportedRegions = make(map[string]bool, 320)
	countryCodesForNonGeographicalRegion = make(map[int]bool, 16)
	carrierOnces     = make(map[string]*sync.Once)
	carrierPrefixMap = make(map[string]*intStringMap)
	geocodingOnces     = make(map[string]*sync.Once)
	geocodingPrefixMap = make(map[string]*intStringMap)
	supportedCallingCodes = make(map[int]bool, 320)
	timezoneOnce sync.Once
	timezoneMap  *intStringArrayMap
	countryCodeToRegion map[int][]string
)
var ErrEmptyMetadata = errors.New("empty metadata")
func readFromRegexCache(key string) (*regexp.Regexp, bool) {
	regCacheMutex.RLock()
	v, ok := regexCache[key]
	regCacheMutex.RUnlock()
	return v, ok
}
func writeToRegexCache(key string, value *regexp.Regexp) {
	regCacheMutex.Lock()
	regexCache[key] = value
	regCacheMutex.Unlock()
}
func regexFor(pattern string) *regexp.Regexp {
	regex, found := readFromRegexCache(pattern)
	if !found {
		regex = regexp.MustCompile(pattern)
		writeToRegexCache(pattern, regex)
	}
	return regex
}
func readFromNanpaRegions(key string) (struct{}, bool) {
	v, ok := nanpaRegions[key]
	return v, ok
}
func writeToNanpaRegions(key string, val struct{}) {
	nanpaRegions[key] = val
}
func readFromRegionToMetadataMap(key string) (*PhoneMetadata, bool) {
	v, ok := regionToMetadataMap[key]
	return v, ok
}
func writeToRegionToMetadataMap(key string, val *PhoneMetadata) {
	regionToMetadataMap[key] = val
}
func readFromCountryCodeToNonGeographicalMetadataMap(key int) (*PhoneMetadata, bool) {
	v, ok := countryCodeToNonGeographicalMetadataMap[key]
	return v, ok
}
func writeToCountryCodeToNonGeographicalMetadataMap(key int, v *PhoneMetadata) {
	countryCodeToNonGeographicalMetadataMap[key] = v
}
func loadMetadataFromFile(
	regionCode string,
	countryCallingCode int) error {
	metadataCollection, err := MetadataCollection()
	if err != nil {
		return err
	} else if currMetadataColl == nil {
		currMetadataColl = metadataCollection
	}
	metadataList := metadataCollection.GetMetadata()
	if len(metadataList) == 0 {
		return ErrEmptyMetadata
	}
	for _, meta := range metadataList {
		region := meta.GetId()
		if region == "001" {
			writeToCountryCodeToNonGeographicalMetadataMap(int(meta.GetCountryCode()), meta)
		} else {
			writeToRegionToMetadataMap(region, meta)
		}
	}
	return nil
}
var (
	currMetadataColl *PhoneMetadataCollection
	reloadMetadata   = true
)
func MetadataCollection() (*PhoneMetadataCollection, error) {
	if !reloadMetadata {
		return currMetadataColl, nil
	}
	rawBytes, err := decodeUnzipString(metadataData)
	if err != nil {
		return nil, err
	}
	var metadataCollection = &PhoneMetadataCollection{}
	err = proto.Unmarshal(rawBytes, metadataCollection)
	reloadMetadata = false
	return metadataCollection, err
}
func extractPossibleNumber(number string) string {
	if VALID_START_CHAR_PATTERN.MatchString(number) {
		start := VALID_START_CHAR_PATTERN.FindIndex([]byte(number))[0]
		number = number[start:]
		indices := UNWANTED_END_CHAR_PATTERN.FindIndex([]byte(number))
		if len(indices) > 0 {
			number = number[0:indices[0]]
		}
		indices = SECOND_NUMBER_START_PATTERN.FindIndex([]byte(number))
		if len(indices) > 0 {
			number = number[0:indices[0]]
		}
		return number
	}
	return ""
}
func isViablePhoneNumber(number string) bool {
	if len(number) < MIN_LENGTH_FOR_NSN {
		return false
	}
	return VALID_PHONE_NUMBER_PATTERN.MatchString(number)
}
func normalize(number string) string {
	if VALID_ALPHA_PHONE_PATTERN.MatchString(number) {
		return normalizeHelper(number, ALPHA_PHONE_MAPPINGS, true)
	}
	return NormalizeDigitsOnly(number)
}
func normalizeBytes(number *Builder) *Builder {
	normalizedNumber := normalize(number.String())
	b := number.Bytes()
	copy(b[0:len(normalizedNumber)], []byte(normalizedNumber))
	return NewBuilder(b)
}
func NormalizeDigitsOnly(number string) string {
	return normalizeDigits(number, false  )
}
var arabicIndicNumberals = map[rune]rune{
	'٠':      '0',
	'۰':      '0',
	'١':      '1',
	'۱':      '1',
	'٢':      '2',
	'۲':      '2',
	'٣':      '3',
	'۳':      '3',
	'٤':      '4',
	'۴':      '4',
	'٥':      '5',
	'۵':      '5',
	'٦':      '6',
	'۶':      '6',
	'٧':      '7',
	'۷':      '7',
	'٨':      '8',
	'۸':      '8',
	'٩':      '9',
	'۹':      '9',
	'\uFF10': '0',
	'\uFF11': '1',
	'\uFF12': '2',
	'\uFF13': '3',
	'\uFF14': '4',
	'\uFF15': '5',
	'\uFF16': '6',
	'\uFF17': '7',
	'\uFF18': '8',
	'\uFF19': '9',
}
func normalizeDigits(number string, keepNonDigits bool) string {
	buf := number
	var normalizedDigits = NewBuilder(nil)
	for _, c := range buf {
		if unicode.IsDigit(c) {
			if v, ok := arabicIndicNumberals[c]; ok {
				normalizedDigits.WriteRune(v)
			} else {
				normalizedDigits.WriteRune(c)
			}
		} else if keepNonDigits {
			normalizedDigits.WriteRune(c)
		}
	}
	return normalizedDigits.String()
}