The phone-number library is an interface to the Libphonenumber with some extra sugar. It allows to validate, inspect and generate phone numbers.
To use phone-number in your project, add the following to dependencies section of
project.clj
or build.boot
:
[io.randomseed/phone-number "8.12.21-0"]
For deps.edn
add the following as an element of a map under :deps
or
:extra-deps
key:
io.randomseed/phone-number {:mvn/version "8.12.21-0"}
You can also download JAR from Clojars.
Additionally you can use (in your development profile) if you want to utilize specs and spec-integrated generators provided by the phone-number:
org.clojure/spec.alpha {:mvn/version "0.2.194"}
org.clojure/test.check {:mvn/version "1.1.0"}
A phone number is an abstract that can be a string, an integer number (with the
accompanying region specification), a specially crafted map or a PhoneNumber
object
(which is the internal representation).
For regular operations (like validating a single number or searching for phone numbers in strings) it is enough to use data we already have (like a string or a map).
However, when the performance is important and there is a number of different
operations to be executed on a single phone number it is advised to explicitly
convert the number to its internal representation using the
phone-number.core/number
function:
(require '[phone-number.core :as phone])
(let [n (phone/number "+44 29 2018 3133")] …)
(let [n (phone/number "29 2018 3133" :phone-number.region/gb)] …)
(let [n (phone/number 2920183133 :phone-number.region/gb)] …)
Other forms of a phone number that are acceptable as arguments by most of the functions this library provides include:
"+44 29 2018 3133"
),2920183133
),PhoneNumber
object:{:phone-number/number #<Phonenumber$PhoneNumber@3edea9e6>}
* with region code and national number format:
{:phone-number/region :gb
:phone-number.format/national "2920183133"}
* with calling code and national number format:
{:phone-number/calling-code 44
:phone-number.format/national "2920183133"}
* with international number format:
{:phone-number.format/international "+44 2920183133"}
Note that in case of natural numbers the additional region information is required (most of the functions will accept it as their second calling argument).
In the examples above some regions were set using namespace-qualified keywords and some were not. This is due to namespace inference when it comes to specifying phone number properties that are expressed as keywords.
When the dynamic variable
phone-number.core/*inferred-namespaces*
is set to true
(which is the default setting) all functions that require keyword
arguments will automatically enrich simple keywords to be namespace-qualified. That
affects:
:pl
becomes :phone-number.region/pl
),:mobile
becomes :phone-number.type/mobile
),:international
becomes :phone-number.format/international
),:short
becomes :phone-number.tz-format/short
).To get some specific property of a phone number use one of the functions grouped in
phone-number.core
namespace.
There is also the info
function that produces
a map with most of the properties:
(require '[phone-number.core :as phone])
(phone/info "+44 29 2018 3133")
{:phone-number/country-code 44,
:phone-number/geographical? true,
:phone-number/location "Cardiff",
:phone-number/possible? true,
:phone-number/region :phone-number.region/gb,
:phone-number/dialing-region :phone-number.region/gb,
:phone-number.dialing-region/derived? true,
:phone-number.dialing-region/defaulted? false,
:phone-number.dialing-region/valid-for? true,
:phone-number/type :phone-number.type/fixed-line,
:phone-number/valid? true,
:phone-number.format/e164 "+442920183133",
:phone-number.format/international "+44 29 2018 3133",
:phone-number.format/national "029 2018 3133",
:phone-number.format/raw-input "+44 29 2018 3133",
:phone-number.format/rfc3966 "tel:+44-29-2018-3133",
:phone-number.tz-format/full-standalone ("Greenwich Mean Time"),
:phone-number.tz-format/id ("Europe/London"),
:phone-number.tz-format/short-standalone("GMT"),
:phone.number.short/possible? false,
:phone.number.short/valid? false}
The info
function (like most of the functions operating on phone numbers) takes an
additional, second argument which should be a region code. It is used only when
the given phone number was expressed in a format that cannot provide such information
(a string without calling code, a natural number, a map without any entry containing
region or calling code).
(require '[phone-number.core :as phone])
(phone/info "0491 570 006" :phone-number.region/au)
{:phone-number/calling-code 61,
:phone-number/carrier "Telstra",
:phone-number/geographical? false,
:phone-number/possible? true,
:phone-number/region :phone-number.region/au,
:phone-number/dialing-region :phone-number.region/au,
:phone-number.dialing-region/derived? true,
:phone-number.dialing-region/defaulted? false,
:phone-number.dialing-region/valid-for? true,
:phone-number/type :phone-number.type/mobile,
:phone-number/valid? true,
:phone-number.format/e164 "+61491570006",
:phone-number.format/international "+61 491 570 006",
:phone-number.format/national "0491 570 006",
:phone-number.format/raw-input "0491 570 006",
:phone-number.format/rfc3966 "tel:+61-491-570-006",
:phone-number.tz-format/full-standalone ("Central Australia Time"
"Australian Central Western Time"
"Lord Howe Time"
"Western Australia Time"
"Eastern Australia Time"
"Christmas Island Time"
"Cocos Islands Time"),
:phone-number.tz-format/id ("Australia/Adelaide"
"Australia/Eucla"
"Australia/Lord_Howe"
"Australia/Perth"
"Australia/Sydney"
"Indian/Christmas"
"Indian/Cocos"),
:phone-number.tz-format/short-standalone ("ACT"
"ACWT"
"LHT"
"AWT"
"AET"
"CIT"
"CCT"),
:phone.number.short/possible? false,
:phone.number.short/valid? false}
It is worth to note that the time zone information was presented in English (being
the default locale for the system). That behavior can be changed with a third,
optional argument, which should be a java.util.Locale
instance or a value that can
be converted to it (a string, a keyword, a symbol).
(require '[phone-number.core :as phone])
(phone/info "0491 570 006" :au :pl)
{:phone-number/calling-code 61,
:phone-number/carrier "Telstra",
:phone-number/geographical? false,
:phone-number/possible? true,
:phone-number/region :phone-number.region/au,
:phone-number/dialing-region :phone-number.region/au,
:phone-number.dialing-region/derived? true,
:phone-number.dialing-region/defaulted? false,
:phone-number.dialing-region/valid-for? true,
:phone-number/type :phone-number.type/mobile,
:phone-number/valid? true,
:phone-number.format/e164 "+61491570006",
:phone-number.format/international "+61 491 570 006",
:phone-number.format/national "0491 570 006",
:phone-number.format/raw-input "0491 570 006",
:phone-number.format/rfc3966 "tel:+61-491-570-006",
:phone-number.tz-format/full-standalone ("Czas środkowoaustralijski"
"Czas środkowo-zachodnioaustralijski"
"Lord Howe"
"Czas zachodnioaustralijski"
"Czas wschodnioaustraliski"
"Christmas Island Time"
"Cocos Islands Time"),
:phone-number.tz-format/id ("Australia/Adelaide"
"Australia/Eucla"
"Australia/Lord_Howe"
"Australia/Perth"
"Australia/Sydney"
"Indian/Christmas"
"Indian/Cocos"),
:phone-number.tz-format/short-standalone ("ACT"
"ACWT"
"LHT"
"AWT"
"AET"
"CIT"
"CCT"),
:phone.number.short/possible? false,
:phone.number.short/valid? false}
There is a special class of phone numbers called short numbers. These include all
of the special, short phone numbers used mostly for emergency purposes but also
for local services (like taxis). In the examples above we could see the
keys belonging to the :phone-number.short/
namespace which are describing short
number properties. If the number is not a short number the information map will only
contain :phone-number.short/valid?
and :phone-number.short/possible?
keys.
Short number example:
(require '[phone-number.core :as phone])
(phone/info "997" :pl)
{:phone-number/calling-code 48,
:phone-number/geographical? false,
:phone-number/possible? false,
:phone-number/region :phone-number.region/pl,
:phone-number/dialing-region :phone-number.region/pl,
:phone-number.dialing-region/derived? true,
:phone-number.dialing-region/defaulted? false,
:phone-number.dialing-region/valid-for? true,
:phone-number/type :phone-number.type/unknown,
:phone-number/valid? false,
:phone-number.format/e164 "+48997",
:phone-number.format/international "+48 997",
:phone-number.format/national "997",
:phone-number.format/raw-input "997",
:phone-number.format/rfc3966 "tel:+48-997",
:phone-number.short/carrier-specific? false,
:phone-number.short/cost :phone-number.cost/toll-free,
:phone-number.short/emergency? true,
:phone-number.short/possible? true,
:phone-number.short/sms-service? false,
:phone-number.short/to-emergency? true,
:phone-number.short/valid? true}
Some functions will require phone number type to be given. In is easy to get all the supported types via global variable:
(require '[phone-number.core :as phone])
phone/types
#{:phone-number.type/fixed-line
:phone-number.type/fixed-line-or-mobile
:phone-number.type/mobile
:phone-number.type/pager
:phone-number.type/personal
:phone-number.type/premium-rate
:phone-number.type/shared-cost
:phone-number.type/toll-free
:phone-number.type/uan
:phone-number.type/unknown
:phone-number.type/voicemail
:phone-number.type/voip}
Note that :phone-number.type/unknown
is valid as a property but not valid as an
argument.
Region code is alphabetic, two-letter keyword that allows phone-number functions to create, generate and match phone numbers. It is also used for reporting.
Region codes can be translated to country calling codes which can be observed in
international phone number notations (with the plus sign in front of the number). For
example the region code :pl
(or phone-number.region/pl
) will be represented as
+48
country code prefix.
It is possible to get all of the supported region codes with the
phone-number.core/regions
global variable.
Dialing region code (a.k.a calling region code) is a region code that some of the functions use as a supplementary information to establish certain properties of a number. Semantically it describes where the call is made from (what is its origin).
It is common to use dialing region when testing or validating short phone numbers
since their properties depend on the originating region. For example the number 112
is a valid short number (see the :phone-number.short/valid?
key in an info map)
when dialed from Poland but not from USA.
Dialing region codes may be passed directly to functions that make use of it (and
that is the first and prioritized way to obtain this information) but they can also
be taken from the global dynamic variable
phone-number.core/*default-dialing-region*
. If the phone number is in a form of
a map with :phone-number/dialing-region
key present then a value associated with it
will be tried before (but only if this property is not derived nor defaulted).
In case of phone-number.core/info
and phone-number.core/short-info
there is
another source of getting a dialing region code which is by derivation from a region
code of the number. It is tried when there is no dialing region passed as an
argument, no default dialing region set and no dialing region read from a map (if
a phone number is a map). The derivation is enabled by default but can be controlled
using the phone-number.core/*info-dialing-region-derived*
dynamic variable.
The value of dialing region will affect all of the calculated properties of the
checked number that depend on it but not the one returned by the
phone-number.core/valid?
function. In its case one have to use ternary variant for
the dialing region to be taken into consideration (even passing nil
to make the
function use the default). The reason behind it is that it is very rare need to test
a regular number for validity with a different dialing region. In the majority of
cases the returned value will be false
and it could be a potential point of failure
(or misunderstanding), especially when some default dialing region is present.
Calling code is a prefix number used to create regional or global phone number assignation. There are two types of calling codes supported:
It is possible for a phone number to have a calling code (which is a global one) but not a region code.
There are just a few functions that calling codes can be used with directly. In such cases they are expressed as positive, natural numbers.
phone-number.core/country-codes
.phone-number.core/net-codes
.phone-number.core/calling-codes
.To get the calling code of a phone number use the
phone-number.core/calling-code
function.
Phone numbers can be presented in different formats. To get all possible formats use
the phone-number.core/formats
global
variable:
(require '[phone-number.core :as phone])
phone/formats
#{:phone-number.format/e164
:phone-number.format/international
:phone-number.format/national
:phone-number.format/raw-input
:phone-number.format/rfc3966
:phone-number.format/raw-input}
To get the phone number representation in a specific format use the
phone-number.core/format
function:
(require '[phone-number.core :as phone])
(phone/format "+442920183133" :rfc3966)
"tel:+44-29-2018-3133"
Some phone numbers can be indirectly associated with time zones (via geographical
locations of the lines or carrier's local offices locations). To get all possible
formats of time zones use the
phone-number.core/tz-formats
global variable:
(require '[phone-number.core :as phone])
phone/tz-formats
#{:phone-number.tz-format/full
:phone-number.tz-format/full-standalone
:phone-number.tz-format/id
:phone-number.tz-format/narrow
:phone-number.tz-format/narrow-standalone
:phone-number.tz-format/short
:phone-number.tz-format/short-standalone}
To get time zone information for a phone number in a specified format use the
phone-number.core/time-zones
function:
(require '[phone-number.core :as phone])
(phone/time-zones "+442920183133" nil :full)
("Greenwich Mean Time")
We can observe that the result is a collection of strings. That's because some phone numbers can be assigned to more than one time zone.
To validate a phone number use the following functions:
phone-number.core/valid?
,phone-number.core/invalid?
,phone-number.core/possible?
,phone-number.core/impossible?
.(require '[phone-number.core :as phone])
(phone/valid? 8081570001 :gb) ; => true
(phone/valid? "+448081570001") ; => true
(phone/valid? 8081570001 :pl) ; => false
(phone/valid? "8081570001") ; => false
(phone/possible? "8081570001") ; => false
(phone/possible? "8081570001" :gb) ; => true
(phone/possible? "8081570001" :pl) ; => true
Additionally there are variants for short numbers:
To generate samples of phone numbers with optional predicates controlling the
properties of data use the
phone-number.core/generate
function. It
tries to get the most probable samples (having the most digits randomized yet meeting
the given criteria) with optional deterministic factor (random seed).
There are also phone number generators associated with many of the existing specs that make use of this function.
(require '[phone-number.core :as phone])
(phone/generate)
{:phone-number/info {:phone-number/country-code 213,
:phone-number/geographical? false,
:phone-number/possible? true,
:phone-number/region :phone-number.region/dz,
:phone-number/dialing-region :phone-number.region/dz,
:phone-number.dialing-region/derived? true,
:phone-number.dialing-region/defaulted? false,
:phone-number.dialing-region/valid-for? false,
:phone-number/type :phone-number.type/unknown,
:phone-number/valid? false,
:phone-number.format/e164 "+213181525997",
:phone-number.format/international "+213 181525997",
:phone-number.format/national "181525997",
:phone-number.format/rfc3966 "tel:+213-181525997",
:phone.number.short/possible? false,
:phone.number.short/valid? false},
:phone-number/number #<Phonenumber$PhoneNumber@3edea9e6>,
:phone-number.sample/digits ["+213" nil "181525997"],
:phone-number.sample/hits 10,
:phone-number.sample/max-samples 1000,
:phone-number.sample/random-seed 7521527664400716800,
:phone-number.sample/samples 11}
(require [phone-number.spec :as spec]
[clojure.spec.alpha :as s]
[clojure.spec.gen.alpha :as gen])
(gen/generate (s/gen :phone-number/valid))
{:phone-number/info #delay[{:status :pending, :val nil} 0x3810d15d],
:phone-number/number #<Phonenumber$PhoneNumber@79cc08fb>,
:phone-number.sample/digits ["+7" nil "937627908"],
:phone-number.sample/hits 11,
:phone-number.sample/max-samples 150,
:phone-number.sample/random-seed 7581363778716192180,
:phone-number.sample/samples 27}
(gen/generate (s/gen (s/and :phone-number/possible :phone-number/invalid)))
{:phone-number/info #delay[{:status :pending, :val nil} 0x41c0e225],
:phone-number/number #<Phonenumber$PhoneNumber@36a74c18>,
:phone-number.sample/digits ["+84" nil "0270454"],
:phone-number.sample/hits 8,
:phone-number.sample/max-samples 200,
:phone-number.sample/random-seed -9105741821593959780,
:phone-number.sample/samples 12}
Copyright © 2020 Paweł Wilk
Phone-number is copyrighted software owned by Paweł Wilk (pw@gnu.org). You may redistribute and/or modify this software as long as you comply with the terms of the GNU Lesser General Public License (version 3).
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close