GoLang port of Google's libphonenumber library

Overview

phonenumbers

Build Status codecov GoDoc

golang port of Google's libphonenumber, forked from libphonenumber from ttacon which in turn is a port of the original Java library.

You can see a live demo of the number parsing of the master branch of this library at https://phonenumbers.temba.io/ Compare results with the official Google Java version.

This fork fixes quite a few bugs and more closely follows the official Java implementation. It also adds the buildmetadata cmd to allow for rebuilding the metadata protocol buffers, country code to region maps and timezone prefix maps. We keep this library up to date with the upstream Google repo as metadata changes take place, usually no more than a few days behind official Google releases.

This library is used daily in production for parsing and validation of numbers across the world, so is well maintained. Please open an issue if you encounter any problems, we'll do our best to address them.

Version Numbers

As we don't want to bump our major semantic version number in step with the upstream library, we use independent version numbers than the Google libphonenumber repo. The release notes will mention what version of the metadata a release was built against.

Usage

// parse our phone number
num, err := phonenumbers.Parse("6502530000", "US")

// format it using national format
formattedNum := phonenumbers.Format(num, phonenumbers.NATIONAL)

Rebuilding Metadata and Maps

The buildmetadata command will fetch the latest XML file from the official Google repo and rebuild the go source files containing all the territory metadata, timezone and region maps. (you will need svn installed on your path)

It will rebuild the following files:

metadata_bin.go - contains the protocol buffer definitions for all the various formats across countries etc..

countrycode_to_region_bin.go - contains the information needed to map a contrycode to a region

prefix_to_carrier_bin.go - contains the information needed to map a phone number prefix to a carrier

prefix_to_geocoding_bin.go - contains the information needed to map a phone number prefix to a city or region

prefix_to_timezone_bin.go - contains the information needed to map a phone number prefix to a city or region

% go install github.com/nyaruka/phonenumbers/cmd/buildmetadata
% $GOPATH/bin/buildmetadata
Issues
  • Add MaybeSeparatePhoneFromExtension helper function

    Add MaybeSeparatePhoneFromExtension helper function

    I was looking for a way to separate the extension from the phone number without affecting the formatting of the phone number. The closest that I found was maybeStripExtension so I wrote a new function for myself.

    Do you have any interest in adding it to your project? I'd be happy to adjust it if you have naming conventions that you would like followed.

    opened by richard-rance 6
  • getSupportedCallingCodes method not found

    getSupportedCallingCodes method not found

    Hey, thank you for the great library!

    In the software I am trying to build I was looking for getSupportedCallingCodes that I found in both Java and python versions.

    I tried to get them like this:

    var supportedCallingCodes []int
    for region := range phonenumbers.GetSupportedRegions() {		
    	supportedCallingCodes.append(supportedCallingCodes, phonenumbers.GetCountryCodeForRegion(region))
    }
    

    but in this way I don't get a few codes (e.g. 800,808,883,870,878,881,882,888,979

    Did I missed the method or is there another workaround to get all supported calling codes?

    Regards, -rif

    opened by rif 6
  • Working through fix for CC parsing

    Working through fix for CC parsing

    Related: https://github.com/nyaruka/phonenumbers/issues/80

    Basically reverts https://github.com/nyaruka/phonenumbers/pull/71 as that wasn't the right fix. Adds some more tests and more cleanup code a tad to help readability.

    opened by nicpottier 5
  • Fix regex func

    Fix regex func

    Hi, we've encountered a problem with a phone from Indonesia (62816640000 to be exact) when we tried to get a national number.

    After verification this phone with a JS version (can be checked here, on the latest master https://rawgit.com/googlei18n/libphonenumber/master/javascript/i18n/phonenumbers/demo-compiled.html) we found that Go versions return national number with a country code (when it shouldn't).

    phone: 62816640000
    countyCode: ID
    
    national number:
      Go: 62816640000
      JS: 816640000
    

    The problem lies in a regular expression, 'cause it used slightly in a different way compared to JS. As you can see here google/libphonenumber on the current master (v8.12.13) it checks that some group was found AND it equals to the whole string.

    While in Go it's a simple match nyaruka/phonenumbers on the current master (v1.0.59 (and Go docs confirms this https://pkg.go.dev/regexp#Regexp.MatchString).

    After fixing this regex step, we've encountered a failing test (TestFormatInOriginalFormat) for 49987654321 DE and after another comparison to the JS we found another difference, instead of 49 9876 54321 should be 4998 7654321.

    Thank you. CC: @papisz

    opened by cristaloleg 5
  • 'abcde10' is a US phone number?

    'abcde10' is a US phone number?

    https://play.golang.org/p/5L3Bj6ePfso

    package main
    
    import (
    	"fmt"
    
    	"github.com/nyaruka/phonenumbers"
    )
    
    func main() {
    	num, err := phonenumbers.Parse("abcde10", "US")
    	fmt.Println("Number:", num, err)
    }
    

    Number: country_code:1 national_number:10 <nil>

    opened by or-else 5
  • Corner case with French overseas territory ?

    Corner case with French overseas territory ?

    Hi Guys,

    Could be that I found a corner case that I would like to share with you. I am using your implementation for a telco ticketing system . This telco is exchanging lots of calls from and to the French Overseas territories.

    I do have issues with the result of GetGeocodingForNumber.

    Here is example which hopefully will make the case clear ...

    I have a called number with its national representation like this : 590555008, Its e164 representation looks like this : +590590555008

    When used like this and passing +590590555008 as parameter

    func libPhoneNumberEnrichFields(myNumber string) (string, string, string, string) {
    	var num *phonenumbers.PhoneNumber
    	var err error
    	var geo string
    	num, err = phonenumbers.Parse(myNumber, "FR")
    	if err != nil {
    		global.Logger.WithFields(logrus.Fields{
    			"error": err,
    			"number": myNumber,
    		}).Info("unable to parse number")
    		return "", "", "", ""
    	}
    
    	geo, err = phonenumbers.GetGeocodingForNumber(num, "fr")
    	if err != nil {
    		global.Logger.WithFields(logrus.Fields{
    			"error": err,
    			"number": myNumber,
    		}).Info("unable to GeoCode this number")
    		return "", "", "", ""
    	}
    	cc := strconv.Itoa(int(num.GetCountryCode()))
    	country := phonenumbers.GetRegionCodeForNumber(num)
    	numType := descNumTypeFromType[phonenumbers.GetNumberType(num)]
    	return cc, country, geo, numType
    }
    

    GetGeocodingForNumber is returning me an empty string wo generating any errors.

    However, when you go to ITU web site and open this page: https://www.itu.int/oth/T020200004B/en Then in the pdf format file and click on the link that gives the xls file called MAJNUM.xls:

    https://extranet.arcep.fr/portail/LinkClick.aspx?fileticket=PBA1WK-wnOU%3d&tabid=217&portalid=0&mid=850

    You search for phone number range 059055, you will find the region/location. It should be the location of "Basse-Terre".

    Could you please help me to investigate where is the problem ?

    Is it an ITU data base problem or could it be that I don't use you library properly ?

    I took this example but it seems to apply to all those territories : Guadeloupe, Martinique, Reunion... It applies to all those country codes +262, +590, +594, +596.

    If you could have a look it would be fantastic !

    Thanks Matthieu.

    opened by Matt-Texier 5
  • ParseToNumber parses valid numbers as invalid

    ParseToNumber parses valid numbers as invalid

    When trying to parse a few thousands of numbers we are using ParseToNumber. Unfortunately, we hit a bug which causes ParseToNumber to parse valid phone numbers as invalid. Here is a simple test case that can be used to reproduce the issue. I think for some reason ParseToNumber is not reseting ItalianLeadingZero and NumberOfLeadingZeros which probably is causing the number to be treated as invalid?

    Code to reproduce the issue: https://play.golang.org/p/jSsK71K6Mdg

    opened by bharath23 5
  • OffLine Geocoder support

    OffLine Geocoder support

    Nice golang port of libphonenumber : thanks to make it available as open source.

    I was wondering if you ever investigated the support of PhoneNumberOfflineGeocoder in order to get phone number location ?

    Thanks Matthieu.

    opened by Matt-Texier 5
  • : undefined: proto.InternalMessageInfo

    : undefined: proto.InternalMessageInfo

    go run *.go
    # github.com/gomagicbox/vendor/github.com/nyaruka/phonenumbers
    vendor/github.com/nyaruka/phonenumbers/phonemetadata.pb.go:108:34: undefined: proto.InternalMessageInfo
    vendor/github.com/nyaruka/phonenumbers/phonemetadata.pb.go:214:37: undefined: proto.InternalMessageInfo
    vendor/github.com/nyaruka/phonenumbers/phonemetadata.pb.go:416:35: undefined: proto.InternalMessageInfo
    vendor/github.com/nyaruka/phonenumbers/phonemetadata.pb.go:676:45: undefined: proto.InternalMessageInfo
    vendor/github.com/nyaruka/phonenumbers/phonenumber.pb.go:173:33: undefined: proto.InternalMessageInfo
    
    
    opened by snowdream 5
  • broken countrycode detection in v1.0.60

    broken countrycode detection in v1.0.60

    Hi,

    thanks for the useful library!

    I got a number which gets parsed correctly in v1.0.59, but not anymore in v1.0.60.

    The call is to Parse("6282240080000", "ID"), which returns +626282240080000, but it should detect that the 62 is already present and make it +6282240080000. The original number is possible and valid according to https://rawgit.com/googlei18n/libphonenumber/master/javascript/i18n/phonenumbers/demo-compiled.html but the new number (+6262822...) is possible but not(!) valid.

    A shorter version of the number (62822400800) does get parsed and formatted correctly.

    This shows the problem:

    diff --git a/phonenumbers_test.go b/phonenumbers_test.go
    index a7e16bd..dc58af3 100644
    --- a/phonenumbers_test.go
    +++ b/phonenumbers_test.go
    @@ -1308,6 +1308,9 @@ func TestParsing(t *testing.T) {
                    {"+2203693200", "", "+2203693200"},
                    {"0877747666", "ID", "+62877747666"},
                    {"62816640000", "ID", "+62816640000"},
    +
    +               {"62822400800", "ID", "+62822400800"},
    +               {"6282240080000", "ID", "+6282240080000"},
            }
     
            for _, tc := range tests {
    
    opened by alicebob 4
  • Bump dependencies to latest versions

    Bump dependencies to latest versions

    This was done by doing:

    $ go get -u github.com/golang/protobuf
    $ go mod tidy
    $ git commit
    $ go get -u github.com/aws/aws-lambda-go
    $ go mod tidy
    $ git commit
    
    opened by alex 4
  • Incorrect national number result when dealing with certain phone number format input (ID)

    Incorrect national number result when dealing with certain phone number format input (ID)

    In ID there's old phone number that have only 10 digits (in national format excluding country code) .e.g. 0812456789.

    It produces different results compared with Google Java Version when the input using this format 62812456789.

    image

    image

    Thanks.

    opened by amakmurr 1
  • Non-Lite Protos

    Non-Lite Protos

    Hi, I'm trying to include a phonenumbers.PhoneNumber proto in another proto file (a v3 file that is not using LITE_RUNTIME) like so:

    // phone_number.proto
    syntax = "proto3";
    
    package phoneproto;
    
    option go_package="github.com/foo/bar/phoneproto";
    
    import "github.com/nyaruka/phonenumbers/phonenumber.proto";
    
    message PhoneNumberRequest {
        phonenumbers.PhoneNumber phone_number = 1;
    }
    

    but i'm getting an error when compiling to go:

    phone_number.proto: Files that do not use optimize_for = LITE_RUNTIME cannot import files which do use this option.  This file is not lite, but it imports "github.com/nyaruka/phonenumbers/phonenumber.proto" which is.
    

    I really like that protos are available, but it would be nice to be able to reuse your proto files that don't use LITE_RUNTIME.

    opened by dhulihan 2
  • Partial number formatting

    Partial number formatting

    Is there a way to format a number that is not complete?

    For example, the following COMPLETE number works fine

        iso := "US"
        phone := "2345678901"
        num, _ := phonenumbers.Parse(phone, iso)
        formatted := phonenumbers.Format(num, phonenumbers.NATIONAL)
        fmt.Printf("%s\n", formatted)
    
    (234) 567-8901
    

    However, if I instead pass a PARTIAL number, it loses all formatting.

        iso := "US"
        phone := "23456789"
        num, _ := phonenumbers.Parse(phone, iso)
        formatted := phonenumbers.Format(num, phonenumbers.NATIONAL)
        fmt.Printf("%s\n", formatted)
    
    23456789
    

    I would like it if that would spit out:

    (234) 567-89
    

    Since I want to use this for as the user types their phone number in, displaying it in a proper format.

    Is this doable with this library?

    enhancement 
    opened by nathan-fiscaletti 3
  • Area Code not evaluated

    Area Code not evaluated

    func GetLengthOfNationalDestinationCode(number *PhoneNumber) int ... https://github.com/nyaruka/phonenumbers/blob/master/phonenumbers.go Line 944

    if len(numberGroups) <= 3 { return 0 }

    ... but numberGroups evalueates to e.g.: []string {"49", "30", "1234567"} with len == 3

    so GetLengthOfNationalDestinationCode(..) returns always 0.

    The comment states:

    // The pattern will start with "+COUNTRY_CODE " so the first group // will always be the empty string (before the + symbol) and the // second group will be the country calling code. The third group // will be area code if it is not the last group.

    which seems to be wrong in this case. Comparison should be written as follows:

    if len(numberGroups) <= 2 { return 0 }

    A small test program shows how it should work (as i understand):

    package main
    
    import (
    	"fmt"
    	"log"
    
    	"github.com/nyaruka/phonenumbers"
    )
    
    
    func main() {
    	phone := "+14061234567"
    	country := "US"
    	metadata, err := phonenumbers.Parse(phone, country)
    	if err != nil {
    		log.Printf("error parsing phone: %s", err)
    	}
    
    	nationalSignificantNumber := phonenumbers.GetNationalSignificantNumber(metadata)
    	var areaCode string
    	var subscriberNumber string
    
    	areaCodeLength := phonenumbers.GetLengthOfGeographicalAreaCode(metadata)
    	if areaCodeLength > 0 {
    		areaCode = nationalSignificantNumber[0:areaCodeLength]
    		subscriberNumber = nationalSignificantNumber[areaCodeLength:]
    	} else {
    		areaCode = ""
    		subscriberNumber = nationalSignificantNumber
    	}
    
    	fmt.Printf("%+v\n", metadata)
    
    	fmt.Printf("NationalNumber:            %+v\n", *metadata.NationalNumber)
    	fmt.Printf("NationalSignificantNumber: %+v\n", nationalSignificantNumber)
    	fmt.Printf("AreaCode:                  %+v\n", areaCode)
    	fmt.Printf("SubscriberNumber:          %+v\n", subscriberNumber)
    	fmt.Printf("CountryCode:               %+v\n", *metadata.CountryCode)
    	fmt.Printf("IsPossible:                %+v\n", phonenumbers.IsPossibleNumber(metadata))
    	fmt.Printf("IsValid:                   %+v\n", phonenumbers.IsValidNumber(metadata))
    	fmt.Printf("NationalFormatted:         %+v\n", phonenumbers.Format(metadata, phonenumbers.NATIONAL))
    	fmt.Printf("InternationalFormatted:    %+v\n", phonenumbers.Format(metadata, phonenumbers.INTERNATIONAL))
    }
    
    without change the result shows an empty AreaCode.
    
    with best regards
    Hans S, Kula
    
    
    
    opened by moglio 2
Releases(v1.1.0)
Serial-locate - A simple tool for searching the COM port

serial-locate A simple tool for searching the COM port Usage Direct query serial

Dirk Arnez 0 Jan 18, 2022
Golemon - A Go port of the lemon parser generator

Go lemon port A port of the Lemon Parser to Go. State This work was done entirel

null 9 May 18, 2022
Goridge is high performance PHP-to-Golang codec library which works over native PHP sockets and Golang net/rpc package.

Goridge is high performance PHP-to-Golang codec library which works over native PHP sockets and Golang net/rpc package. The library allows you to call Go service methods from PHP with a minimal footprint, structures and []byte support.

Spiral Scout 1.1k Aug 5, 2022
Govalid is a data validation library that can validate most data types supported by golang

Govalid is a data validation library that can validate most data types supported by golang. Custom validators can be used where the supplied ones are not enough.

null 61 Apr 22, 2022
Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs.

go-attr Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs. This package provides user frien

Shyamsunder Rathi 27 Jul 5, 2022
A Go (golang) library for parsing and verifying versions and version constraints.

go-version is a library for parsing versions and version constraints, and verifying versions against a set of constraints. go-version can sort a collection of versions properly, handles prerelease/beta versions, can increment versions, etc.

HashiCorp 1.2k Aug 8, 2022
A library for diffing golang structures

Diff A library for diffing golang structures and values. Utilizing field tags and reflection, it is able to compare two structures of the same type an

R3 Labs 595 Aug 6, 2022
A well tested and comprehensive Golang statistics library package with no dependencies.

Stats - Golang Statistics Package A well tested and comprehensive Golang statistics library / package / module with no dependencies. If you have any s

Montana Flynn 2.5k Aug 8, 2022
go-sundheit:A library built to provide support for defining service health for golang services

A library built to provide support for defining service health for golang services. It allows you to register async health checks for your dependencies and the service itself, and provides a health endpoint that exposes their status.

AppsFlyer 487 Jul 16, 2022
Cogger is a standalone binary and a golang library that reads an internally tiled geotiff

Cogger is a standalone binary and a golang library that reads an internally tiled geotiff (optionally with overviews and masks) and rewrites it

Airbus DS GEO S.A. 71 Jun 23, 2022
A concurrent rate limiter library for Golang based on Sliding-Window rate limiter algorithm.

ratelimiter A generic concurrent rate limiter library for Golang based on Sliding-window rate limitng algorithm. The implementation of rate-limiter al

Narasimha Prasanna HN 216 Jul 27, 2022
MNA - stands for mobile number assignment - a small zero external dependency golang library that is used to identify mobile number assignment in tanzania

MNA - stands for mobile number assignment - a small zero external dependency golang library that is used to identify mobile number assignment in tanzania

TECHCRAFT TECHNOLOGIES LIMITED 8 Nov 29, 2021
Easy to use, light enough, good performance Golang library

指令使用 特性 简单易用、足够轻量,避免过多的外部依赖,最低兼容 Window 7 等老系统 快速上手 安装 $ go get github.com/sohaha/zlsgo HTTP 服务 // main.go

影浅 508 Jul 24, 2022
GoDynamic can load and run Golang dynamic library compiled by -buildmode=shared -linkshared

GoDynamic can load and run Golang dynamic library compiled by -buildmode=shared -linkshared How does it work? GoDynamic works like a dynamic

pkujhd 8 Aug 8, 2022
The main goal of this code is to create a basic dnstap printing tool based on the golang-dnstap library.

dnstap-parse The main goal of this code is to create a basic dnstap printing tool based on the golang-dnstap library. The output is supposed to mimic

Patrik Lundin 1 Nov 14, 2021
A prototype code-generator library for golang.

A prototype code-generator library for golang.

PL Pery 7 Jul 28, 2022
Gopher protocol library for Golang

Gopher protocol library for Golang This is a standards compliant Gopher library for the Go programming language implementing the RFC 1436 specificatio

Rebecca 0 Nov 13, 2021
A golang library to validate and format swiss social security numbers

s3n is a golang library to validate and format swiss social security numbers (aka. AVS in french and AHV in german).

Julien M'Poy 0 Nov 15, 2021
maskerito is masking library for golang. Especially for indonesia dictionary.

maskerito maskerito is masking library for golang. Especially for indonesia dictionary. Library maskerito provides a library to do masking struct and

Firda Safridi 3 Jul 28, 2022