Clojure: validating phone numbers


Sometimes you need to validate phone numbers, googlei18n/libphonenumber is a Java library for doing just that (and more). Thanks to Clojure's great java interop using this library in your project is straightforward.

First, we add the com.googlecode.libphonenumber dependency to the leiningen project.clj file.

(defproject phone-number-validation "0.1.0-SNAPSHOT"
  :dependencies [[com.googlecode.libphonenumber/libphonenumber "8.9.9"]

Then we import the PhoneNumberUtil class and use the .parse method which takes: an instance of PhoneNumberUtil, a phone number string, and a default region string (which in this case we have just left empty). It returns a PhoneNumber which we then passe into the .isValidNumber method for validation.

Note: According to the source code PhoneNumberUtil/getInstance implements the singleton pattern. So, calling it multiple times only results in one instance being created.

(ns core
  (:import [com.google.i18n.phonenumbers PhoneNumberUtil]))

(defn valid-number? [number]
  (->> (.parse (PhoneNumberUtil/getInstance) number "")
       (.isValidNumber (PhoneNumberUtil/getInstance))))

(valid-number? "+41446681800")

=> true

(valid-number? "+41543")

=> false

The above works well enough so far. But, what if we try something more "obviously wrong"?

(valid-number? "+41")

=>
Execution error (NumberParseException) at com.google.i18n.phonenumbers.PhoneNumberUtil/parseHelper (PhoneNumberUtil.java:3151).
The string supplied did not seem to be a phone number.

We get an exception. If we look at the .parse method's source code this is expected behaviour throws NumberParseException. We can make our valid-number? function handle this exception with try and catch.

(ns core
  (:import [com.google.i18n.phonenumbers PhoneNumberUtil]
           [com.google.i18n.phonenumbers NumberParseException]))

(defn valid-number? [number]
  (try
    (->> (.parse (PhoneNumberUtil/getInstance) number "")
         (.isValidNumber (PhoneNumberUtil/getInstance)))
    (catch NumberParseException e false)))

(valid-number? "+41446681800")

=> true

(valid-number? "+41543")

=> false

(valid-number? "+41")

=> false

(valid-number? "rubbish")

=> false

Great our function now handles any string we throw at it! That wraps up our short introduction to googlei18n/libphonenumber.