License plate

Brazilian vehicle license plates, in the Mercosul (LLLNLNN) and pre-Mercosul (LLLNNNN) patterns.

  • Parity matrix

Validate

Validates a license plate in the old format (ABC1234) or the Mercosul format (ABC1D23), in any case, with or without a hyphen or space.

  • options.format restricts the check to one format: "LLLNNNN" (old, ABC1234) or "LLLNLNN" (Mercosul, ABC1D23), the codes licensePlate.getFormat returns and licensePlate.generate takes. Without it, or with any other value, both formats are accepted. Until 2.4.0 the option did not exist and both formats were always accepted.
  • Any other sequence of letters and digits, or extra characters, makes it invalid.
  • The mask (whitespace, ., - or /, alone or in a run) is accepted only between the third character and the last four, whitespace around the plate is ignored, and the check is case-insensitive.
  • A mask character anywhere else, or any other character (A@BC1234, an emoji), makes the plate invalid instead of being stripped. Until 2.4.0 such characters were stripped (A@B#C1$2%3^4 was true).
  • licensePlate.getFormat returns null exactly when this returns false.
  • The withdrawn motorcycle sequence LLLNNLN (ABC12D3) is invalid.
ParameterTypeRequired
valuestringyes
optionsIsValidLicensePlateOptionsno
options.formatLicensePlateFormatno
returnsboolean

Check if a license plate is valid. Accepts the old Brazilian format (ABC-1234) and the Mercosul format (ABC1D23), with or without a mask, in any case. The mask (whitespace, ., - or /, alone or in a run) is accepted only between the third character and the last four; any other character (@, an emoji, a separator anywhere else) makes the plate invalid instead of being stripped.

The optional format of the second argument (IsValidLicensePlateOptions) restricts the check to one of them: "LLLNNNN" for the old format or "LLLNLNN" for the Mercosul one, the names getFormatLicensePlate returns. It works like the type argument of the Python library's is_valid, whose values are named "old_format" and "mercosul" there. Those names are not formats here: without format, or with any other value, a plate in either format is valid.

import { isValidLicensePlate } from '@brazilian-utils/brazilian-utils';

isValidLicensePlate('ABC1234'); // true (Brazilian format)
isValidLicensePlate('ABC-1234'); // true (Brazilian format with hyphen)
isValidLicensePlate('ABC 1234'); // true (whitespace mask)
isValidLicensePlate('ABC1D23'); // true (Mercosul format)
isValidLicensePlate('ABC12D3'); // false (not a Mercosul sequence)
isValidLicensePlate('ABC1234EXTRA'); // false (too many characters)
isValidLicensePlate('A-BC1234'); // false (the mask sits after the third character only)
isValidLicensePlate('ABC1234!'); // false (any other character is rejected)
isValidLicensePlate('ABC1D23', { format: 'LLLNLNN' }); // true
isValidLicensePlate('ABC1234', { format: 'LLLNLNN' }); // false (an old format plate)
isValidLicensePlate('ABC-1234', { format: 'LLLNNNN' }); // true

Source: Resolução CONTRAN nº 969/2022, Anexos.

Code: brazilian-utils/javascript
Try it with JavaScript isValidLicensePlate
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (48) and the result in each library licensePlate.isValid

Format

Formats a license plate in upper case. Old-format plates (LLLNNNN) get a hyphen (ABC-1234). Mercosul plates (LLLNLNN) have no separator.

  • A partial value is formatted as far as it goes, so the function works as an input mask: the hyphen shows up as soon as the fourth character is a digit (abc1 gives ABC-1), and a fifth character that is a letter keeps the Mercosul form (abc1d gives ABC1D).
  • Any character that is not an ASCII letter or digit is dropped first, and only the first 7 remain. Unlike licensePlate.isValid, the mask may sit anywhere.
  • Returns an empty string when the value cannot start a valid plate (1234567, abc12d3, abc1da2).
  • A value that is not a string returns an empty string.
ParameterTypeRequired
valuestringyes
returnsstring

Format a license plate. Old Brazilian plates (LLLNNNN) get a hyphen; Mercosul plates (LLLNLNN) are returned without a separator.

  • Returns '' when the value cannot start a valid plate.
  • A partial value is formatted progressively, so the function works as an input mask: the hyphen shows up as soon as the fourth character is a digit, and a fifth character that is a letter keeps the Mercosul form.
import { formatLicensePlate } from '@brazilian-utils/brazilian-utils';

formatLicensePlate('abc1234'); // 'ABC-1234'
formatLicensePlate('abc1d23'); // 'ABC1D23'
formatLicensePlate('abc1'); // 'ABC-1' (a partial value is formatted as far as it goes)
formatLicensePlate('abc1d'); // 'ABC1D'
Code: brazilian-utils/javascript
Try it with JavaScript formatLicensePlate
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (28) and the result in each library licensePlate.format

Parse

Removes every character that is not an ASCII letter or digit from a license plate, upper-cases it and caps it at 7 characters (abc-1234 gives ABC1234).

  • It does not validate: use licensePlate.isValid for that. The mask may sit anywhere, unlike in licensePlate.isValid.
  • A value that is not a string returns an empty string.
ParameterTypeRequired
valuestringyes
returnsstring

Remove separators from a license plate, normalize it to uppercase, and cap it to 7 characters.

import { parseLicensePlate } from '@brazilian-utils/brazilian-utils';

parseLicensePlate('abc-1234'); // 'ABC1234'
Code: brazilian-utils/javascript
Try it with JavaScript parseLicensePlate
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (11) and the result in each library licensePlate.parse

Generate

Generates a valid random license plate, unformatted.

  • format is LLLNLNN (Mercosul, the default) or LLLNNNN (old format). Any other value falls back to the default.
  • The fifth character of a Mercosul plate is drawn from K to Z. A to J is used only to convert an old-format plate (Resolução CONTRAN nº 969/2022, Anexo II, item 2), so a new plate never carries it. Until 2.4.0 it could be any letter.
  • A format outside the two literals falls back to the default, so the result is always a plate licensePlate.isValid accepts. Version 2.3.0 used an unknown string verbatim.
  • It uses a non-cryptographic random source.
ParameterTypeRequired
formatGenerateLicensePlateFormatno
returnsstring

Generate a valid random license plate in the chosen format.

  • format (GenerateLicensePlateFormat, an alias of LicensePlateFormat): 'LLLNLNN' (Mercosul, the default) or 'LLLNNNN' (the old Brazilian format). Any other value falls back to the default.
  • The letter in the fifth position of a Mercosul plate is drawn from K to Z: A to J is used only to convert an old format plate (Anexo II, item 2, of Resolução CONTRAN nº 969/2022), so a new plate never carries it.
import { generateLicensePlate } from '@brazilian-utils/brazilian-utils';

generateLicensePlate(); // 'ABC1K23' (Mercosul, the default)
generateLicensePlate('LLLNNNN'); // 'ABC1234'
generateLicensePlate('LLLNNLN'); // 'ABC1K23' (a format outside the two in circulation falls back to the default)

Source: Resolução CONTRAN nº 969/2022.

Code: brazilian-utils/javascript
Try it with JavaScript generateLicensePlate
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (6) and the result in each library licensePlate.generate

Convert to mercosul

Converts an old-format plate (LLLNNNN) to the Mercosul format (LLLNLNN). The 5th character, a digit, becomes a letter, with 0 to 9 mapping to A to J (ABC1234 becomes ABC1C34). The result is upper-cased and has no mask.

The conversion follows the table of Anexo II of Resolução CONTRAN nº 969/2022. Every other character stays as it is.

  • The plate is read like licensePlate.isValid reads it: any case, the mask (ABC-1234, ABC 1234) accepted, whitespace around it ignored, and a mask character or any other character in another position makes it invalid. Until 2.4.0 such characters were stripped, so A-BC1234 was converted.
  • It returns an empty string, not null, when the value is not a valid old-format plate: a plate that is already Mercosul (ABC1D23), the withdrawn LLLNNLN sequence, a wrong length or an invalid value.

Pending decision

The reference (JS) also accepts the hyphen mask (ABC-1234). Other libraries reject it. See the open decision in docs/findings.md.

Pending decision

For a plate that is already Mercosul or is not a valid old-format plate, the reference (JS) returns an empty string. Most libraries return null. See the open decision in docs/findings.md.

ParameterTypeRequired
valuestringyes
returnsstring

Convert an old format Brazilian license plate (LLLNNNN) to the Mercosul format (LLLNLNN). The 5th digit becomes a letter, 0 through 9 mapping to A through J.

  • Returns "" when the value is not a valid old format license plate.
import { convertLicensePlateToMercosul } from '@brazilian-utils/brazilian-utils';

convertLicensePlateToMercosul('ABC1234'); // 'ABC1C34'
convertLicensePlateToMercosul('abc-1234'); // 'ABC1C34'
convertLicensePlateToMercosul('ABC1D23'); // '' (already Mercosul)

Source: Resolução CONTRAN nº 969/2022, Anexo II.

Code: brazilian-utils/javascript
Try it with JavaScript convertLicensePlateToMercosul
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (20) and the result in each library licensePlate.convertToMercosul

Get format

Detects the format of a license plate: LLLNNNN for the old format, LLLNLNN for Mercosul.

  • The plate is read like licensePlate.isValid reads it: any case, whitespace around it ignored, and the mask (whitespace, ., - or /) accepted only between the third character and the last four. A mask character anywhere else, or any other character, makes the value invalid. Until 2.4.0 such characters were stripped, so A-BC1234 gave LLLNNNN.
  • Returns null when the value is not 7 letters and digits in one of the two formats, including the withdrawn LLLNNLN sequence.
  • It returns null exactly when licensePlate.isValid returns false.

Pending decision

Erlang returns named formats instead of the patterns. See the open decision in docs/findings.md.

ParameterTypeRequired
valuestringyes
returnsLicensePlateFormat | null

Detect the normalized format of a license plate: 'LLLNNNN' for the old Brazilian format, 'LLLNLNN' for Mercosul.

  • Returns null when the value, separators removed, is not 7 letters and digits in one of the two formats.
  • Exports the LicensePlateFormat type, which generateLicensePlate re-exports as GenerateLicensePlateFormat.
import { getFormatLicensePlate } from '@brazilian-utils/brazilian-utils';

getFormatLicensePlate('ABC-1234'); // 'LLLNNNN'
getFormatLicensePlate('ABC1D23'); // 'LLLNLNN'
getFormatLicensePlate('ABC12D3'); // null (not a Mercosul sequence)
getFormatLicensePlate('INVALID'); // null
getFormatLicensePlate('ABC1234EXTRA'); // null (too many characters)
Code: brazilian-utils/javascript
Try it with JavaScript getFormatLicensePlate
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (14) and the result in each library licensePlate.getFormat

Specification

Summary

Vehicle license plates are the front and rear plates fixed to a vehicle. A plate has 7 letters and digits.

Validation rules

Mercosul standard

  1. The plate has 7 letters and digits in the LLLNLNN pattern.

Pre-Mercosul standard

  1. The plate has 7 letters and digits in the LLLNNNN pattern, in two groups:
    • The first group is 3 letters (A to Z).
    • The second group is 4 digits.

Algorithm

  1. Remove the whitespace at the start and at the end, and the mask characters (whitespace, ., - or /, alone or in a run) between the third character and the last four. A mask character anywhere else, or any other character, makes the plate invalid.
  2. Check that 7 characters remain.
  3. Check that all characters are alphanumeric.
  4. Check that the input follows one of the valid patterns:
    • Mercosul: LLLNLNN
    • Pre-Mercosul: LLLNNNN
  5. If the input follows neither pattern, the license plate is invalid.

Regex

  • Raw input (the mask sits between the third character and the last four): ^\s*[A-Za-z]{3}[\s.\-/]*[0-9A-Za-z]{4}\s*$
  • Characters only (pre-Mercosul or Mercosul pattern): ^(?:[A-Z]{3}[0-9]{4}|[A-Z]{3}[0-9][A-Z][0-9]{2})$

Examples

  • Valid: ABC1234 (pre-Mercosul standard)
  • Valid: ABC1D23 (Mercosul standard)
  • Invalid: AB12345 (does not follow any valid format)
  • Invalid: ABCD123 (incorrect number of letters)
  • Invalid: ABC123 (fewer than 7 characters)
  • Invalid: ABC12D4 (incorrect character order)

Official sources

See also RENAVAM

Last updated on

On this page