Skip to content

Commit

Permalink
Phone parser (#33)
Browse files Browse the repository at this point in the history
* data source links applied, type renaming

* phone parser

---------

Co-authored-by: ivan-lemiashonak <[email protected]>
  • Loading branch information
ilemiashonak and ilemiashonak authored May 29, 2023
1 parent 84081a4 commit 067c1d3
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,5 @@ func main() {
- Email [(part of RFC5322)](https://tools.ietf.org/html/rfc5322) - [wiki](https://en.wikipedia.org/wiki/Email_address)
- Timezone [(RFC6557 IANA timezones)](https://www.iana.org/time-zones) - [wiki](https://en.wikipedia.org/wiki/Time_zone)
- Languages [(ISO 639-1)](https://www.iso.org/standard/22109.html) - [wiki](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes); [(ISO 639-2)](https://www.iso.org/standard/4767.html) - [wiki](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes), [data source](https://datahub.io/core/language-codes/r/language-codes-3b2.json)
- BCP47 language tags [(wiki)](https://en.wikipedia.org/wiki/IETF_language_tag), [rfc](https://www.rfc-editor.org/info/bcp47)
- Dial Codes [(E.164)](https://www.itu.int/rec/T-REC-E.164-201203-I!Sup6/en) - [wiki](https://en.wikipedia.org/wiki/E.164), [data source](https://datahub.io/core/country-codes/r/country-codes.json)
- BCP47 language tags [(wiki)](https://en.wikipedia.org/wiki/IETF_language_tag), [rfc](https://www.rfc-editor.org/info/bcp47)
2 changes: 1 addition & 1 deletion bcp47_language/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ components:
example: en-US
type: string
format: bcp47-language
x-go-type: github.com/mikekonan/go-types/bcp47_language.Language
x-go-type: github.com/mikekonan/go-types/v2/bcp47_language.Language
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ require (
golang.org/x/text v0.9.0
gopkg.in/guregu/null.v4 v4.0.0
)

require (
github.com/golang/protobuf v1.3.2 // indirect
github.com/nyaruka/phonenumbers v1.1.7 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/nyaruka/phonenumbers v1.1.7 h1:5UUI9hE79Kk0dymSquXbMYB7IlNDNhvu2aNlJpm9et8=
github.com/nyaruka/phonenumbers v1.1.7/go.mod h1:DC7jZd321FqUe+qWSNcHi10tyIyGNXGcNbfkPvdp1Vs=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg=
Expand Down
39 changes: 39 additions & 0 deletions phone/number.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import (
"database/sql/driver"
"encoding/json"
"fmt"
"github.com/mikekonan/go-types/v2/country"
"strconv"

"github.com/nyaruka/phonenumbers"
)

// Number represents a phone number type
Expand Down Expand Up @@ -61,3 +64,39 @@ func (number *Number) UnmarshalJSON(data []byte) error {
func (number Number) String() string {
return string(number)
}

// StrictParse is Parse analogue with phone number region consistency check: fails if passed country is not matches parsed one
func StrictParse(rawPhone string, country country.Alpha2Code) (DialCode, Number, error) {
var parsed, err = phonenumbers.Parse(rawPhone, country.String())
if err != nil {
return "", "", err
}

var valid = phonenumbers.IsValidNumber(parsed)
if !valid {
return "", "", fmt.Errorf(`%s phone number is not valid for %s region`, rawPhone, country.String())
}

var dialCode = DialCode(strconv.Itoa(int(parsed.GetCountryCode())))
if err = dialCode.Validate(); err != nil {
return "", "", err
}

return dialCode, Number(strconv.FormatUint(parsed.GetNationalNumber(), 10)), nil
}

// Parse matches passed 'country' string representation to digits and searches for it at the beginning of 'rawPhone'.
// If not found - consider whole passes 'rawPhone' as Number and use matched one 'country' as DialCode
func Parse(rawPhone string, country country.Alpha2Code) (DialCode, Number, error) {
var parsed, err = phonenumbers.Parse(rawPhone, country.String())
if err != nil {
return "", "", err
}

var dialCode = DialCode(strconv.Itoa(int(parsed.GetCountryCode())))
if err = dialCode.Validate(); err != nil {
return "", "", err
}

return dialCode, Number(strconv.FormatUint(parsed.GetNationalNumber(), 10)), nil
}
43 changes: 43 additions & 0 deletions phone/number_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package phone
import (
"encoding/json"
"fmt"
"github.com/mikekonan/go-types/v2/country"
"testing"
)

Expand Down Expand Up @@ -67,3 +68,45 @@ func TestNumber_Value(t *testing.T) {
}
}
}

var parseTestCases = []struct {
testPhoneNumber string
testCountryCode country.Alpha2Code
expectingError bool
}{
{testPhoneNumber: "", testCountryCode: country.Australia.Alpha2Code(), expectingError: true},
{testPhoneNumber: "sdfge5uy2fwdf", testCountryCode: country.Australia.Alpha2Code(), expectingError: true},
{testPhoneNumber: "123", testCountryCode: country.Australia.Alpha2Code(), expectingError: false},
{testPhoneNumber: "375295555555", testCountryCode: country.Belgium.Alpha2Code(), expectingError: false},
{testPhoneNumber: "375295555555", testCountryCode: country.Belarus.Alpha2Code(), expectingError: false},
}

func TestParse(t *testing.T) {
for _, testCase := range parseTestCases {
_, _, actualErr := Parse(testCase.testPhoneNumber, testCase.testCountryCode)
if (actualErr == nil) && testCase.expectingError {
t.Errorf(`PhoneNumber: '%s', CountryCode: '%s'. Error is expected but the result was opposite`, testCase.testPhoneNumber, testCase.testCountryCode)
}
}
}

var strictParseTestCases = []struct {
testPhoneNumber string
testCountryCode country.Alpha2Code
expectingError bool
}{
{testPhoneNumber: "", testCountryCode: country.Australia.Alpha2Code(), expectingError: true},
{testPhoneNumber: "asdgdhf", testCountryCode: country.Australia.Alpha2Code(), expectingError: true},
{testPhoneNumber: "123", testCountryCode: country.Australia.Alpha2Code(), expectingError: true},
{testPhoneNumber: "375295555555", testCountryCode: country.Belgium.Alpha2Code(), expectingError: true},
{testPhoneNumber: "375295555555", testCountryCode: country.Belarus.Alpha2Code(), expectingError: false},
}

func TestParseWithRegionCheck(t *testing.T) {
for _, testCase := range strictParseTestCases {
_, _, actualErr := StrictParse(testCase.testPhoneNumber, testCase.testCountryCode)
if (actualErr == nil) && testCase.expectingError {
t.Errorf(`PhoneNumber: '%s', CountryCode: '%s'. Error is expected but the result was opposite`, testCase.testPhoneNumber, testCase.testCountryCode)
}
}
}
2 changes: 1 addition & 1 deletion swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ components:
example: en-US
type: string
format: bcp47-language
x-go-type: github.com/mikekonan/go-types/bcp47_language.Language
x-go-type: github.com/mikekonan/go-types/v2/bcp47_language.Language
CardDate:
example: 01/06
type: string
Expand Down

0 comments on commit 067c1d3

Please sign in to comment.