# Address Formatting [![Build Status](https://github.com/OpenCageData/address-formatting/actions/workflows/ci.yml/badge.svg)](https://github.com/OpenCageData/address-formatting/actions/workflows/ci.yml) Templates and test cases for address formats used in territories around the world. The templates can be processed in any programming language ([see list of processors](#processing-logic)). ## Example Given a set of address parts: ```yaml house_number: 17 road: Rue du Médecin-Colonel Calbairac neighbourhood: Lafourguette suburb: Toulouse Ouest postcode: 31000 city: Toulouse county: Toulouse state: Midi-Pyrénées country: France country_code: FR ``` We want to compile an address in the format consumers expect: ``` 17 Rue du Médecin-Colonel Calbairac 31000 Toulouse France ``` ## Why Use This? The intended use case is database or geocoding systems (forward, reverse, autocomplete) where we know both the country of the address and the language of the user/reader. The address is displayed to a consumer (for example in an app) and not used to print on an envelope for actual postal delivery. We use it to format output from the [OpenCage Geocoding API](https://opencagedata.com/api). ## Scope **What we handle:** - Incomplete data - Anything with a name (peaks, bridges, bus stops) **What we don't handle** (unlike [physical postal mail](http://www.bitboost.com/ref/international-address-formats.html)): - Apartment/flat numbers, floor numbers - PO boxes - Translating the destination address language (whatever language is input is output) ## Processing Logic Our goal is a series of programming language-independent templates that can be processed by whatever software you like. ### Open-Source Implementations | Language | Repository | Notes | |----------|------------|-------| | Android | [AndroidAddressFormatter](https://github.com/woheller69/AndroidAddressFormatter) | | | Elixir | [ex_address_formatting](https://github.com/dkuku/ex_address_formatting) | | | Go | [address-formatter](https://github.com/timonmasberg/address-formatter) | | | Java | [address-formatter-java](https://github.com/placemarkt/address-formatter-java) | | | JavaScript | [address-formatter](https://github.com/fragaria/address-formatter) | | | Kotlin | [address-formatter-kotlin](https://github.com/bettermile/address-formatter-kotlin) | | | Perl | [Geo-Address-Formatter](https://metacpan.org/release/Geo-Address-Formatter) | | | PHP | [address-formatter-php](https://github.com/predicthq/address-formatter-php) | | | PowerShell | [AddressFormatter](https://github.com/GruberMarkus/AddressFormatter) | Cross-platform | | Python | [addressformatting](https://github.com/pudo/addressformatting/tree/master) | No longer maintained | | Ruby | [address_composer](https://github.com/mirubiri/address_composer) | | | Rust | [address-formatter-rs](https://github.com/antoine-de/address-formatter-rs) | No longer maintained | | Scala | [address-formatter](https://github.com/ben-willis/address-formatter) | | We welcome more language implementations. The more people who use the templates, the more likely bugs will be reported. **If you write a processor**, please submit a pull request adding it to the list. Include this repo as a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) so we all use the same templates/configuration and stay in sync. See [how we do it in the Perl parser](https://github.com/OpenCageData/perl-Geo-Address-Formatter/blob/master/README.md#installation) for an example. ## International Coverage As of March 2024: | Metric | Count | |--------|-------| | Known territories | 251 | | Territories with tests | 251 (100%) | | Territories with rules | 251 (100%) | | Territories without rules or tests | 0 (0%) | This output is generated by `bin/coverage.pl`. Run `bin/coverage.pl -d` for a detailed breakdown. The list of all known territories is in `conf/country_codes.yaml`. > **Note:** The list contains all officially assigned [ISO 3166-1 alpha-2 codes](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements). This is not a political statement about the status of any territory. **We need more language-specific abbreviations.** See `conf/abbreviations`. Pull requests welcome! ## File Format - **Configuration:** [YAML](http://yaml.org/) format - **Templates:** [Mustache](http://mustache.github.io/) with one variation: `{#first}` sections take the first alternative for which a variable could be interpolated Both formats are human-readable, strict, handle escaping, and support comments. YAML allows references ("anchors") to avoid duplication; Mustache allows sub-templates ("partials"). ## How to Add Your Country/Territory ### Step 1: Create Test Cases Edit the `.yaml` testcase for the country/territory in `testcases/countries`. File names correspond to [ISO 3166-1 alpha-2 codes](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) (see `conf/country_codes.yaml`). **To get sample data:** 1. Find an addressed location (house, business, etc.) in your target territory on [OpenStreetMap](https://www.openstreetmap.org) 2. Get the coordinates (lat, long) 3. Enter the coordinates into the [OpenCage Geocoding API demo](https://opencagedata.com/demo) 4. Check the resulting JSON in the *Raw Response* tab ### Step 2: Define Formatting Rules Edit `conf/countries/worldwide.yaml`: - **If your territory uses an existing generic format** (defined at the top of the file): map your `country_code` to the generic template. You may still want to add cleanup code (see the `DE` entry as an example). - **If not**: define a new rule set (which may or may not be generic). You may also need to define new state/region mappings in `conf/state_codes.yaml`. ### Step 3: Test Process the `.yaml` test via a processor (see above) and verify the input produces the desired output. We run these checks automatically against pull requests to prevent regressions. **Questions?** Submit an issue. ## Formatting Rules | Rule | Description | |------|-------------| | `replace:` | Regex operating on input values. Useful for removing bureaucratic cruft like "London Borough of". Prefix with `key=` (e.g., `city=`) to operate only on that key. | | `postformat_replace:` | Regex operating on the final output. | | `add_component:` | Add a component with format `component=XXXX`. | | `change_country:` | Change the country value of the input. Useful for dependent territories. Supports substitutions like `$state`. See `testcases/countries/sh.yaml` for an example. | | `use_country:` | Use the formatting configuration of another country. Useful for dependent territories to avoid duplicating configuration. | ## Roadmap More tests are always needed. For every rule about addresses there are exceptions and edge cases. **Planned features:** - Basic error checking (e.g., ignore values that obviously cannot be postcodes) - Rules for postcode format validation We welcome your pull requests. Together we can address the world! ## License MIT License - see [LICENSE.txt](LICENSE.txt) for details. ## Resources ### Testing Data [Lists of random addresses/postcodes/coordinates](https://opencagedata.com/tools/address-lists) for testing (general or country-specific). ### Further Reading - [Our blog post announcing this project](https://blog.opencagedata.com/post/99059889253/good-looking-addresses-solving-the-berlin-berlin) and the motivations behind it - [Falsehoods Programmers Believe about Addresses](http://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses/) by Michael Tandy ### Related Projects - [OpenStreetMap](https://www.openstreetmap.org) - Open address data - [OpenAddresses](http://openaddresses.io/) - Open address data - [OpenCage Geocoder](https://opencagedata.com) - Convert coordinates to formatted addresses - [what3words](http://what3words.com) - An alternative to traditional addresses --- ## About OpenCage GmbH OpenCage logo We run a worldwide [geocoding API](https://opencagedata.com/api) and [geosearch](https://opencagedata.com/geosearch) service based on open data. [Learn more about us](https://opencagedata.com/about). We also organize [Geomob](https://thegeomob.com), a series of regular meetups for location-based service creators. If you like geo stuff, check out [the Geomob podcast](https://thegeomob.com/podcast/).