{"id":32195985,"url":"https://github.com/randomseed-io/phone-number","last_synced_at":"2026-02-08T14:10:04.698Z","repository":{"id":62435415,"uuid":"266436623","full_name":"randomseed-io/phone-number","owner":"randomseed-io","description":"Phone numbers as data: validate, inspect, search, generate.","archived":false,"fork":false,"pushed_at":"2026-02-01T11:12:01.000Z","size":616,"stargazers_count":18,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-01T13:58:02.474Z","etag":null,"topics":["carrier","clojure","geolocation","i18n","metadata","phone","phone-number","phonenumber","timezone","validation"],"latest_commit_sha":null,"homepage":"https://randomseed.io/software/phone-number","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/randomseed-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-05-23T23:28:33.000Z","updated_at":"2026-02-01T11:12:04.000Z","dependencies_parsed_at":"2023-12-13T23:00:39.998Z","dependency_job_id":"265191ee-abcc-43dc-b2e3-5d85e078cbce","html_url":"https://github.com/randomseed-io/phone-number","commit_stats":{"total_commits":333,"total_committers":2,"mean_commits":166.5,"dds":"0.0030030030030030463","last_synced_commit":"9ae592c0517a92d66534f0f62c291b21f02be58e"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/randomseed-io/phone-number","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randomseed-io%2Fphone-number","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randomseed-io%2Fphone-number/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randomseed-io%2Fphone-number/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randomseed-io%2Fphone-number/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/randomseed-io","download_url":"https://codeload.github.com/randomseed-io/phone-number/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randomseed-io%2Fphone-number/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29232802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T13:49:52.259Z","status":"ssl_error","status_checked_at":"2026-02-08T13:49:18.683Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["carrier","clojure","geolocation","i18n","metadata","phone","phone-number","phonenumber","timezone","validation"],"created_at":"2025-10-22T02:24:22.936Z","updated_at":"2026-02-08T14:10:04.690Z","avatar_url":"https://github.com/randomseed-io.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Phone Number\n\n*Phone numbers as data: validate, inspect, search, generate.*\n\n[![Phone-number on Clojars](https://img.shields.io/clojars/v/io.randomseed/phone-number.svg)](https://clojars.org/io.randomseed/phone-number)\n[![Phone-number on cljdoc](https://cljdoc.org/badge/io.randomseed/phone-number)](https://cljdoc.org/d/io.randomseed/phone-number/CURRENT)\n[![CircleCI](https://dl.circleci.com/status-badge/img/gh/randomseed-io/phone-number/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/randomseed-io/phone-number/tree/master)\n\nA pragmatic, data-oriented Clojure wrapper around Google's Libphonenumber for\nvalidating, inspecting, formatting, searching text, and generating phone numbers. It\ntreats phone numbers as data: most functions accept strings, numbers, `PhoneNumber`\ninstances, or keyword-keyed maps, and return values that are pleasant to pipe\nthrough.\n\n## Features\n\n* Data-first, polymorphic API: phone numbers can be expressed as numbers, strings,\n  `PhoneNumber` objects, or maps.\n\n* Rich, keyword-keyed info maps with optional namespace inference\n  (e.g. a key can be `:phone-number/type` or just `:type`;\n  a type can be `:phone-number.type/mobile` or just `:mobile`).\n\n* Optional enrichment with carrier, location, and time zone data (via libphonenumber add-on\n  modules), exposed through the same data-first API.\n\n* Stable options-map API for text searching (`phone-number.core/find-numbers-opts`),\n  backed by lazy maps (LazyMap) so expensive info can be computed on demand.\n\n* Built-in support for short numbers (e.g. emergency numbers): validation, reachability,\n  and expected cost class.\n\n* Sample generation that returns both the `PhoneNumber` and reproducibility/debug data\n  (including `:phone-number.sample/random-seed` and sampler stats).\n\n* Specs with generators for generative testing, plus structured errors via `ex-info`\n  with `:phone-number/error` in `ex-data`.\n\n## Caveats\n\nIf your program processes a lot of phone numbers and your strategy is to keep them in\na native format (a result of calling `phone-number.core/number`), then be aware that,\nby default, all created `PhoneNumber` objects will have their raw input stored\ninternally.  This affects **comparison** in a way that the object representing\na number `+442920183133` will **not be equal** to the object representing the same\nnumber but with spaces (`+44 2920 183 133`). This is because the equality test is\nbased, among other things, on raw input values, which are also used to generate each\nobject's hash code.\n\nTo work around this, you have two options:\n\n* Use `phone-number.core/number-noraw` on input data to parse numbers without\n  preserving raw inputs.\n\n* Use `phone-number.core/number-noraw` on existing objects to create raw-input-free\n  copies.\n\nOptionally, `phone-number.core/number-optraw` can also be used (especially in\nprocessing pipelines) to preserve raw input only when the created object is\ninitialized from an existing one (an instance of `PhoneNumber`). For other argument\ntypes, the protocol method behaves like `number-noraw`.\n\nSome functions validate their arguments and may throw `clojure.lang.ExceptionInfo` on\ninvalid inputs. Such exceptions include `:phone-number/error` in `ex-data`, which can\nbe used for error classification.\n\n## Sneak peeks\n\n* It **can show information** about phone numbers:\n\n```clojure\n(require '[phone-number.core :as phone])\n\n;; region taken from a phone number\n;; using system's default locale\n\n(phone/info \"+44 29 2018 3133\")\n\n{:phone-number/country-code               44,\n :phone-number/dialing-region             :phone-number.region/gb,\n :phone-number.dialing-region/defaulted?  false,\n :phone-number.dialing-region/derived?    true,\n :phone-number.dialing-region/valid-for?  true,\n :phone-number/geographical?              true,\n :phone-number/location                   \"Cardiff\",\n :phone-number/possible?                  true,\n :phone-number/region                     :phone-number.region/gb,\n :phone-number/type                       :phone-number.type/fixed-line,\n :phone-number/valid?                     true,\n :phone-number.format/e164                \"+442920183133\",\n :phone-number.format/international       \"+44 29 2018 3133\",\n :phone-number.format/national            \"029 2018 3133\",\n :phone-number.format/raw-input           \"+44 29 2018 3133\",\n :phone-number.format/rfc3966             \"tel:+44-29-2018-3133\",\n :phone-number.tz-format/full-standalone  '(\"Greenwich Mean Time\"),\n :phone-number.tz-format/id               '(\"Europe/London\"),\n :phone-number.tz-format/short-standalone '(\"GMT\"),\n :phone.number.short/possible?            false,\n :phone.number.short/valid?               false}\n\n;; region passed as an argument\n;; locale setting passed as an argument\n\n(phone/info \"601 100 601\" :pl :pl)\n\n{:phone-number/country-code               48,\n :phone-number/carrier                    \"Plus\",\n :phone-number/dialing-region             :phone-number.region/pl,\n :phone-number.dialing-region/defaulted?  false,\n :phone-number.dialing-region/derived?    true,\n :phone-number.dialing-region/valid-for?  true,\n :phone-number/geographical?              false,\n :phone-number/location                   \"Polska\",\n :phone-number/possible?                  true,\n :phone-number/region                     :phone-number.region/pl,\n :phone-number/type                       :phone-number.type/mobile,\n :phone-number/valid?                     true,\n :phone-number.format/e164                \"+48601100601\",\n :phone-number.format/international       \"+48 601 100 601\",\n :phone-number.format/national            \"601 100 601\",\n :phone-number.format/raw-input           \"601 100 601\",\n :phone-number.format/rfc3966             \"tel:+48-601-100-601\",\n :phone-number.tz-format/full-standalone  '(\"Czas środkowoeuropejski\"),\n :phone-number.tz-format/id               '(\"Europe/Warsaw\"),\n :phone-number.tz-format/short-standalone '(\"CET\"),\n :phone.number.short/possible?            false,\n :phone.number.short/valid?               false}\n\n(phone/info \"8081 570001\" :gb :en)\n\n{:phone-number/country-code               44,\n :phone-number/dialing-region             :phone-number.region/gb,\n :phone-number.dialing-region/defaulted?  false,\n :phone-number.dialing-region/derived?    true,\n :phone-number.dialing-region/valid-for?  true,\n :phone-number/geographical?              false,\n :phone-number/possible?                  true,\n :phone-number/region                     :phone-number.region/gb,\n :phone-number/type                       :phone-number.type/toll-free,\n :phone-number/valid?                     true,\n :phone-number.format/e164                \"+448081570001\",\n :phone-number.format/international       \"+44 808 157 0001\",\n :phone-number.format/national            \"0808 157 0001\",\n :phone-number.format/raw-input           \"8081 570001\",\n :phone-number.format/rfc3966             \"tel:+44-808-157-0001\",\n :phone-number.tz-format/full-standalone  '(\"Greenwich Mean Time\" \"British Time\"),\n :phone-number.tz-format/id               '(\"Europe/Guernsey\"\n                                            \"Europe/Isle_of_Man\"\n                                            \"Europe/Jersey\"\n                                            \"Europe/London\"),\n :phone-number.tz-format/short-standalone  '(\"GMT\" \"BT\"),\n :phone.number.short/possible?             false,\n :phone.number.short/valid?                false}\n```\n\n* It **validates** phone numbers:\n\n```clojure\n(require '[phone-number.core :as phone])\n\n(phone/valid? 8081570001 :gb)      ; =\u003e true\n(phone/valid? \"+448081570001\")     ; =\u003e true\n(phone/valid? 8081570001 :pl)      ; =\u003e false\n(phone/valid? \"8081570001\")        ; =\u003e false\n\n(phone/possible? \"8081570001\")     ; =\u003e false\n(phone/possible? \"8081570001\" :gb) ; =\u003e true\n(phone/possible? \"8081570001\" :pl) ; =\u003e true\n```\n\n* It **searches** for phone numbers in text (recommended: the stable options-map API):\n\n```clojure\n(require '[phone-number.core :as phone])\n\n(-\u003e\u003e (phone/find-numbers-opts\n      \"Call me at +44 808 157 0001!\" {:region-code :gb\n                                      :leniency    :valid\n                                      :max-tries   1})\n     first\n     (into {}) ;; materialize lazy-map (also forces :phone-number/info)\n     (dissoc :phone-number/number))\n\n;; If you don't want the info map to be generated at all:\n(-\u003e\u003e (phone/find-numbers-opts\n      \"Call me at +44 808 157 0001!\" {:region-code :gb\n                                      :max-tries   1\n                                      :locale-specification false})\n     first\n     (into {})\n     (dissoc :phone-number/number))\n```\n\n* It gives known phone number **formats** and **types**:\n\n```clojure\n(require '[phone-number.core :as phone])\n\nphone/formats\n\n#{:phone-number.format/e164\n  :phone-number.format/international\n  :phone-number.format/national\n  :phone-number.format/raw-input\n  :phone-number.format/rfc3966}\n\nphone/types\n\n#{:phone-number.type/fixed-line\n  :phone-number.type/fixed-line-or-mobile\n  :phone-number.type/mobile\n  :phone-number.type/pager\n  :phone-number.type/personal\n  :phone-number.type/premium-rate\n  :phone-number.type/shared-cost\n  :phone-number.type/toll-free\n  :phone-number.type/uan\n  :phone-number.type/unknown\n  :phone-number.type/voicemail\n  :phone-number.type/voip}\n```\n\n* It **generates** phone numbers:\n\n```clojure\n(phone/generate)\n\n{:phone-number/info\n    {:phone-number/country-code              213,\n     :phone-number/geographical?             false,\n     :phone-number/possible?                 true,\n     :phone-number/region                    :phone-number.region/dz,\n     :phone-number/type                      :phone-number.type/unknown,\n     :phone-number/valid?                    false,\n     :phone-number/dialing-region            :phone-number.region/dz,\n     :phone-number.dialing-region/defaulted? false,\n     :phone-number.dialing-region/derived?   true,\n     :phone-number.dialing-region/valid-for? false,\n     :phone-number.format/e164               \"+213181525997\",\n     :phone-number.format/international      \"+213 181525997\",\n     :phone-number.format/national           \"181525997\",\n     :phone-number.format/rfc3966            \"tel:+213-181525997\",\n     :phone.number.short/possible?           false,\n     :phone.number.short/valid?              false},\n\n :phone-number/number #\u003ccom.google.i18n.phonenumbers.Phonenumber$PhoneNumber@3edea9e6\u003e,\n :phone-number.sample/digits      [\"+213\" nil \"181525997\"],\n :phone-number.sample/hits        10,\n :phone-number.sample/max-samples 1000,\n :phone-number.sample/random-seed 7521527664400716800,\n :phone-number.sample/samples     11}\n\n(require [phone-number.spec       :as spec]\n         [clojure.spec.alpha      :as    s]\n         [clojure.spec.gen.alpha  :as  gen])\n\n(gen/generate (s/gen :phone-number/valid))\n\n{:phone-number/info   #delay[{:status :pending, :val nil} 0x3810d15d],\n :phone-number/number #\u003ccom.google.i18n.phonenumbers.Phonenumber$PhoneNumber@79cc08fb\u003e,\n :phone-number.sample/digits      [\"+7\" nil \"937627908\"],\n :phone-number.sample/hits        11,\n :phone-number.sample/max-samples 150,\n :phone-number.sample/random-seed 7581363778716192180,\n :phone-number.sample/samples     27}\n\n(gen/generate (s/gen (s/and :phone-number/possible :phone-number/invalid)))\n\n{:phone-number/info    #delay[{:status :pending, :val nil} 0x41c0e225],\n :phone-number/number #\u003ccom.google.i18n.phonenumbers.Phonenumber$PhoneNumber@36a74c18\u003e,\n :phone-number.sample/digits      [\"+84\" nil \"0270454\"],\n :phone-number.sample/hits        8,\n :phone-number.sample/max-samples 200,\n :phone-number.sample/random-seed -9105741821593959780,\n :phone-number.sample/samples     12}\n```\n\nAnd more…\n\n## Installation\n\nTo use phone-number in your project, add the following to the dependencies section of\n`project.clj` or `build.boot`:\n\n```clojure\n[io.randomseed/phone-number \"3.23-0\"]\n```\n\nFor `deps.edn`, add the following as an element of a map under the `:deps` or\n`:extra-deps` key:\n\n```clojure\nio.randomseed/phone-number {:mvn/version \"3.23-0\"}\n```\n\nAdditionally, if you want to use the specs and generators provided by phone-number,\nadd the following to your development profile:\n\n```clojure\norg.clojure/spec.alpha {:mvn/version \"0.6.249\"}\norg.clojure/test.check {:mvn/version \"1.1.3\"}\n```\n\nYou can also download the JAR from [Clojars](https://clojars.org/io.randomseed/phone-number).\n\n## Documentation\n\nFull documentation including usage examples is available at:\n\n* https://randomseed.io/software/phone-number/\n\n## License\n\nCopyright © 2020–2026 Paweł Wilk\n\nPhone-number is copyrighted software owned by Paweł Wilk (pw@gnu.org). You may\nredistribute and/or modify this software as long as you comply with the terms of\nthe [GNU Lesser General Public License][LICENSE] (version 3).\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n## Development\n\n[![CircleCI](https://circleci.com/gh/randomseed-io/phone-number.svg?style=svg)](https://circleci.com/gh/randomseed-io/phone-number)\n\n### Building docs\n\n```bash\nmake docs\n```\n\n### Building JAR\n\n```bash\nmake jar\n```\n\n### Rebuilding POM\n\n```bash\nmake pom\n```\n\n### Signing POM\n\n```bash\nmake sig\n```\n\n### Deploying to Clojars\n\n```bash\nmake deploy\n```\n\n### Interactive development\n\n```bash\nbin/repl\n```\n\nStarts a REPL and an nREPL server (the port is stored in `.nrepl-port`).\n\n[LICENSE]:    https://github.com/randomseed-io/phone-number/blob/master/LICENSE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frandomseed-io%2Fphone-number","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frandomseed-io%2Fphone-number","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frandomseed-io%2Fphone-number/lists"}