Skip to content

Instantly share code, notes, and snippets.

@danielrbradley
Last active April 4, 2024 09:36
Show Gist options
  • Star 79 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save danielrbradley/7567269 to your computer and use it in GitHub Desktop.
Save danielrbradley/7567269 to your computer and use it in GitHub Desktop.
Regular Expression to Validate UK Number Plates

Regular Expression to Validate UK Number Plates

Regular Expression

(?<Current>^[A-Z]{2}[0-9]{2}[A-Z]{3}$)|(?<Prefix>^[A-Z][0-9]{1,3}[A-Z]{3}$)|(?<Suffix>^[A-Z]{3}[0-9]{1,3}[A-Z]$)|(?<DatelessLongNumberPrefix>^[0-9]{1,4}[A-Z]{1,2}$)|(?<DatelessShortNumberPrefix>^[0-9]{1,3}[A-Z]{1,3}$)|(?<DatelessLongNumberSuffix>^[A-Z]{1,2}[0-9]{1,4}$)|(?<DatelessShortNumberSufix>^[A-Z]{1,3}[0-9]{1,3}$)|(?<DatelessNorthernIreland>^[A-Z]{1,3}[0-9]{1,4}$)|(?<DiplomaticPlate>^[0-9]{3}[DX]{1}[0-9]{3}$)

For use in JavaScript (with named groups removed):

(^[A-Z]{2}[0-9]{2}\s?[A-Z]{3}$)|(^[A-Z][0-9]{1,3}[A-Z]{3}$)|(^[A-Z]{3}[0-9]{1,3}[A-Z]$)|(^[0-9]{1,4}[A-Z]{1,2}$)|(^[0-9]{1,3}[A-Z]{1,3}$)|(^[A-Z]{1,2}[0-9]{1,4}$)|(^[A-Z]{1,3}[0-9]{1,3}$)|(^[A-Z]{1,3}[0-9]{1,4}$)|(^[0-9]{3}[DX]{1}[0-9]{3}$)

Update: V2 - 2019-07-18

  • Added Northern Ireland support. Thanks to @harry-jones
  • Added Diplomatic Plate support. Thanks to @CTaylor94
  • Add variation for JS with named groups removed. Thanks to @glcheetham

Source information

DVLA website

Rules

Current

It consists of two letters, followed by two numbers that help identify the age of the vehicle, and three letters at the end.

Prefix

It consists of one letter that helps identify the age of the vehicle, followed by one, two or three numbers, and three letters at the end.

Suffix

It consists of three letters, followed by one, two or three numbers, and a single letter at the end that helps identify the age of the vehicle.

Dateless

It can consist of up to four numbers followed by up to three letters, or vice versa. The maximum number of characters is six.

A dateless plate could be more formally described as four alternative rules:

  1. Long Number Prefix: It can consist of up to four numbers followed by up to two letters.
  2. Short Number Prefix: It can consist of up to three numbers followed by up to three letters.
  3. Long Number Suffix: It can consist of up to two letters followed by up to four numbers.
  4. Short Number Suffix: It can consist of up to three letters followed by up to three numbers.

Northern Ireland

Northern Ireland style registrations also fall within the dateless range. These consist of three letters followed by up to four numbers. All Northern Ireland registrations contain either the letter I or Z.

Diplomatic Number Plates

Ran into requirement for UK Diplomatic Number plate regex, which is explained here. Essentially cars operated by foreign embassies have unique vehicle registration. An example diplomatic plate could be "101D234", which would be used for a vehicle issues to the embassy of Afghanistan.

The first three numbers in the format represent the country or international organisation, for example Sweden; which has been allocated the numbers 259. In some cases, for larger countries, a range of numbers issued, for example Spain, which has been issued the range 253 to 255.

The letter in the number plate represents the type of person the vehicle is allocated to, with D being used for diplomats and X for non-diplomatic accredited personnel.

The final three numbers in the number plate are identifiers, with the range 101 to 399 being used for diplomats, 400 to 699 for non-diplomatic staff, and 700 to 99 for consular staff.

See this wikipedia list for country codes.

Validation Examples

This can be tested using regexpal.com. Tip: set multiline flag to true

== Valid Current Style ==
AB51ABC
-- Invalid Current Style --
- Missing First Letter = Prefix e.g. A51ABC
- Extra First Letter -
ABC54ABC
- Missing Number -
AB5ABC
- Extra Number -
AB543ABC
- Missing Last Letter -
AB54AB
- Extra Last Letter -
AB54ABCD
== Valid Prefix ==
A123ABC
A12ABC
A1ABC
-- Invalid Prefix --
- Missing First Letter = Dateless e.g. 123ABC
- Extra First Letter -
AB1ABC
- Missing Numbers -
AABC
- Extra Numbers -
A1234ABC
- Missing Last Letter -
A1AB
- Extra Last Letter -
A1ABCD
== Valid Suffix ==
ABC123A
ABC12A
ABC1A
-- Invalid Suffix --
- Missing First Letter -
AB1A
AB123A
- Extra First Letter
ABCD1A
ABCD123A
- Missing Numbers -
ABCA
- Extra Numbers -
ABC1234A
- Missing Last Letter = Dateless e.g. ABC123
- Extra Last Letter -
ABC1AB
== Valid Dateless ==
1ABC
ABC1
1234A
A1234
1234AB
AB1234
123ABC
ABC123
-- Invalid Dateless --
- Missing Numbers -
ABC
- Extra Numbers -
12345A
A12345
- Missing Letters -
1
123
1234
- Extra Letters
1ABCD
ABCD1
- More than 6 characters -
1234ABC
ABCD123
== Valid Northern Ireland ==
ABC123
ABC1234
-- Invalid Northern Ireland --
- Extra Letter -
ABCD123
- Extra Number -
ABC12345
== Valid Diplomatic ===
101D234
123X456
-- Invalid Diplomatic --
- Not D or X in middle -
123A456
- Extra numbers -
1234D567
123X4567
@chrissy-dev
Copy link

chrissy-dev commented Mar 8, 2018

@karwalr @glcheetham @O-mkar I'd say it's probably safer to remove spaces before running this.

In JS:

var registration = "sh61 jjx";
// registration is equal to "sh61 jjx"
registration = registration.replace(/\s+/g, "").toUpperCase();
// registration is now equal to "SH61JJX"
// You can now run it against the regex ...

Copy link

ghost commented Jul 17, 2019

Added support for UK Diplomatic Number Platers 👍

https://gist.github.com/CTaylor94/718936df2af9c597b023c0d11c4d5f1b

@xitude
Copy link

xitude commented Jul 5, 2020

Would this work with PHP preg_match?

@danielrbradley
Copy link
Author

Would this work with PHP preg_match?

Yes, based on a quick test using an online for PHP tool all versions work correctly.

@saied-nawaz
Copy link

Created this swift package based off this, hopefully might be useful for someone https://github.com/saied-nawaz/vrm-validator

@xitude
Copy link

xitude commented Dec 8, 2020

Would this work with PHP preg_match?

Yes, based on a quick test using an online for PHP tool all versions work correctly.

Could you provide that as code snip? I cannot get it to work, unfortunately.

@DocandteeTom
Copy link

DocandteeTom commented Jun 29, 2021

Hi,

Here's what I'm using to allow spaces, hopefully useful to someone else. AFAIK they're in the right places.

(?<Current>^[A-Z]{2}[0-9]{2}\s?[A-Z]{3}$)|(?<Prefix>^[A-Z][0-9]{1,3}\s?[A-Z]{3}$)|(?<Suffix>^[A-Z]{3}\s?[0-9]{1,3}[A-Z]$)|(?<DatelessLongNumberPrefix>^[0-9]{1,4}\s?[A-Z]{1,2}$)|(?<DatelessShortNumberPrefix>^[0-9]{1,3}\s?[A-Z]{1,3}$)|(?<DatelessLongNumberSuffix>^[A-Z]{1,2}\s?[0-9]{1,4}$)|(?<DatelessShortNumberSufix>^[A-Z]{1,3}\s?[0-9]{1,3}$)|(?<DatelessNorthernIreland>^[A-Z]{1,3}\s?[0-9]{1,4}$)|(?<DiplomaticPlate>^[0-9]{3}\s?[DX]{1}\s?[0-9]{3}$)

To require spaces, simply change all cases of \s? to \s

Using PHP preg_match, case insensitive through the use of i on the end of the expression:

<?php
$expression = '/^(?<Current>^[A-Z]{2}[0-9]{2}\s?[A-Z]{3}$)|(?<Prefix>^[A-Z][0-9]{1,3}\s?[A-Z]{3}$)|(?<Suffix>^[A-Z]{3}\s?[0-9]{1,3}[A-Z]$)|(?<DatelessLongNumberPrefix>^[0-9]{1,4}\s?[A-Z]{1,2}$)|(?<DatelessShortNumberPrefix>^[0-9]{1,3}\s?[A-Z]{1,3}$)|(?<DatelessLongNumberSuffix>^[A-Z]{1,2}\s?[0-9]{1,4}$)|(?<DatelessShortNumberSufix>^[A-Z]{1,3}\s?[0-9]{1,3}$)|(?<DatelessNorthernIreland>^[A-Z]{1,3}\s?[0-9]{1,4}$)|(?<DiplomaticPlate>^[0-9]{3}\s?[DX]{1}\s?[0-9]{3}$)/i';

$test = 'BD51 SMR';

if (preg_match($expresion, $test)) {
    echo 'Valid registration:' . strtoupper($test);
}

@EltonWhybrow
Copy link

Nice one! Very useful 👍👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment