Logo do Brazilian Utils

Utils library for Brazilian-specific businesses.

Erlang

Build

Requires Erlang/OTP 25 or newer (tested on OTP 25, 26 and 27).

rebar3 compile

Generate the API documentation with:

rebar3 edoc

Usage

All functions are available through the brutils facade module and operate on UTF-8 binaries:

1> brutils:is_valid_cpf(<<"82178537464">>).
true

Each utility also lives in its own module (brutils_cpf, ...) with the unsuffixed names (brutils_cpf:is_valid/1), if you prefer to depend on the domain module directly.

Utilities

CPF

is_valid_cpf

Returns whether the verifying checksum digits of the given CPF (Brazilian Individual Taxpayer Number) match its base number. This function does not verify the existence of the CPF; it only validates the format of the string.

Args:

Returns:

Example:

1> brutils:is_valid_cpf(<<"82178537464">>).
true
2> brutils:is_valid_cpf(<<"00011122233">>).
false

format_cpf

Formats a valid CPF for display, adding the standard visual aid symbols (XXX.XXX.XXX-XX).

Args:

Returns:

Example:

1> brutils:format_cpf(<<"82178537464">>).
{ok,<<"821.785.374-64">>}
2> brutils:format_cpf(<<"00011122233">>).
{error,invalid}

remove_symbols_cpf

Removes the formatting symbols . and - from a CPF string. Only those two characters are removed; anything else is kept unchanged.

Args:

Returns:

Example:

1> brutils:remove_symbols_cpf(<<"000.111.222-33">>).
<<"00011122233">>

generate_cpf

Generates a random valid CPF as a numbers-only binary.

Returns:

Example:

1> brutils:generate_cpf().
<<"44635843700">>
2> brutils:generate_cpf().
<<"06854668417">>

CNPJ

is_valid_cnpj

Returns whether the verifying checksum digits of the given CNPJ (Brazilian Company Registration Number) match its base number. Both the numeric format and the 2026 alphanumeric format (digits and uppercase letters in the first 12 characters) are supported. This function does not verify the existence of the CNPJ; it only validates the format of the string.

Args:

Returns:

Example:

1> brutils:is_valid_cnpj(<<"03560714000142">>).
true
2> brutils:is_valid_cnpj(<<"00111222000133">>).
false
3> brutils:is_valid_cnpj(<<"6Q4E392H000190">>).
true

format_cnpj

Formats a valid CNPJ for display, adding the standard visual aid symbols (XX.XXX.XXX/XXXX-XX).

Args:

Returns:

Example:

1> brutils:format_cnpj(<<"03560714000142">>).
{ok,<<"03.560.714/0001-42">>}
2> brutils:format_cnpj(<<"00111222000133">>).
{error,invalid}

remove_symbols_cnpj

Removes the formatting symbols ., / and - from a CNPJ string. Only those three characters are removed; anything else is kept unchanged.

Args:

Returns:

Example:

1> brutils:remove_symbols_cnpj(<<"03.560.714/0001-42">>).
<<"03560714000142">>

generate_cnpj

Generates a random valid CNPJ. An optional branch number can be given (non-negative integer or digits-only binary; defaults to 1), and an optional alphanumeric flag switches to the 2026 alphanumeric format, where the branch may also contain uppercase letters and invalid branches are replaced by 0001.

Returns:

Example:

1> brutils:generate_cnpj().
<<"95427181000143">>
2> brutils:generate_cnpj(1234).
<<"44122762123483">>
3> brutils:generate_cnpj(<<"AB12">>, true).
<<"X8641237AB1272">>

PIS

is_valid_pis

Returns whether the verifying check digit of the given PIS/PASEP (Brazilian social integration program number) matches its base number. This function does not verify the existence of the PIS; it only validates the format of the string.

Args:

Returns:

Example:

1> brutils:is_valid_pis(<<"12056798818">>).
true
2> brutils:is_valid_pis(<<"12056798810">>).
false
3> brutils:is_valid_pis(<<"00000000000">>).
true

format_pis

Formats a valid PIS for display, adding the standard visual aid symbols (NNN.NNNNN.NN-N).

Args:

Returns:

Example:

1> brutils:format_pis(<<"12056798818">>).
{ok,<<"120.56798.81-8">>}
2> brutils:format_pis(<<"12056798810">>).
{error,invalid}

remove_symbols_pis

Removes the formatting symbols . and - from a PIS string. Only those two characters are removed; anything else is kept unchanged.

Args:

Returns:

Example:

1> brutils:remove_symbols_pis(<<"120.56798.81-8">>).
<<"12056798818">>

generate_pis

Generates a random valid PIS as a numbers-only binary. The base is drawn uniformly with zero included, so results may start with zeros.

Returns:

Example:

1> brutils:generate_pis().
<<"99360519414">>
2> brutils:generate_pis().
<<"95319303914">>

CNH

is_valid_cnh

Returns whether the given CNH (Brazilian driver's license registration number, 2022 layout) is valid: after stripping every non-digit character, exactly 11 digits must remain and both verifying check digits must match the base number. Earlier CNH layouts are not supported. This function does not verify the existence of the CNH; it only validates the format of the string.

Unlike the CPF/CNPJ/PIS validators, symbols do not need to be removed first: formatted input such as <<"987654321-00">> is accepted, and letters are stripped rather than rejected.

Args:

Returns:

Example:

1> brutils:is_valid_cnh(<<"98765432100">>).
true
2> brutils:is_valid_cnh(<<"987654321-00">>).
true
3> brutils:is_valid_cnh(<<"12345678901">>).
false
4> brutils:is_valid_cnh(<<"A2C45678901">>).
false

RENAVAM

is_valid_renavam

Returns whether the given RENAVAM (Brazilian vehicle registration number) is valid: exactly 11 digits whose verifying check digit matches the base number. This function does not verify the existence of the RENAVAM; it only validates the format of the string.

Unlike is_valid_cnh, symbols are not stripped: any non-digit character (space, dash, letter) makes the input invalid.

Args:

Returns:

Example:

1> brutils:is_valid_renavam(<<"86769597308">>).
true
2> brutils:is_valid_renavam(<<"12345678901">>).
false
3> brutils:is_valid_renavam(<<"867695973-08">>).
false
4> brutils:is_valid_renavam(<<"12345678 901">>).
false

CEP

A CEP (Brazilian postal code) has no check digit: validation is purely structural — exactly 8 digits — and says nothing about whether the postal code actually exists. Address lookup functions (via the ViaCEP API) are planned for a future release.

is_valid_cep

Returns whether the given CEP is valid: a binary of exactly 8 digits. Any 8-digit sequence is structurally valid, including repeated ones like <<"00000000">>.

Args:

Returns:

Example:

1> brutils:is_valid_cep(<<"01310200">>).
true
2> brutils:is_valid_cep(<<"1310200">>).
false
3> brutils:is_valid_cep(<<"01310-200">>).
false

format_cep

Formats a valid CEP for display, adding the standard dash (NNNNN-NNN).

Args:

Returns:

Example:

1> brutils:format_cep(<<"01310200">>).
{ok,<<"01310-200">>}
2> brutils:format_cep(<<"1234567">>).
{error,invalid}

remove_symbols_cep

Removes the formatting symbols . and - from a CEP string. Only those two characters are removed; anything else is kept unchanged.

Args:

Returns:

Example:

1> brutils:remove_symbols_cep(<<"01310-200">>).
<<"01310200">>

generate_cep

Generates a random CEP as a numbers-only binary. Each digit is drawn independently, so results may start with zeros.

Returns:

Example:

1> brutils:generate_cep().
<<"22648357">>
2> brutils:generate_cep().
<<"98885103">>

Phone

Brazilian phone numbers are handled without the +55 country code and with the two-digit DDD (area code) included. Two shapes exist:

TypeDigitsShape
mobile11DDD (1–9 each) + 9 + 8 digits
landline10DDD (1–9 each) + one digit 2–5 + 7 digits

is_valid_phone

Returns whether the given phone number is valid — either shape for the one-argument form, or a specific one when the type atom (mobile or landline) is given. It does not verify that the number actually exists. Symbols are not stripped — clean the input with remove_symbols_phone/1 first.

Args:

Returns:

Example:

1> brutils:is_valid_phone(<<"11994029275">>).
true
2> brutils:is_valid_phone(<<"1635014415">>).
true
3> brutils:is_valid_phone(<<"11994029275">>, mobile).
true
4> brutils:is_valid_phone(<<"11994029275">>, landline).
false

format_phone

Formats a valid phone number for display: DDD in parentheses (no space after them) and a dash before the last four digits.

Args:

Returns:

Example:

1> brutils:format_phone(<<"11994029275">>).
{ok,<<"(11)99402-9275">>}
2> brutils:format_phone(<<"1635014415">>).
{ok,<<"(16)3501-4415">>}

remove_symbols_phone

Removes common phone punctuation from a string: (, ), -, + and spaces. Dots are NOT removed.

Args:

Returns:

Example:

1> brutils:remove_symbols_phone(<<"+55 (11) 99402-9275">>).
<<"5511994029275">>

remove_international_dialing_code

Removes the Brazilian international dialing code (55) from a phone number: if the input contains 55 and is longer than 11 characters (ignoring spaces), the first occurrence of 55 is removed; otherwise the input is returned unchanged. Note the sharp edges: a leading + is kept, and the removed 55 is the first occurrence wherever it sits.

Args:

Returns:

Example:

1> brutils:remove_international_dialing_code(<<"5511994029275">>).
<<"11994029275">>
2> brutils:remove_international_dialing_code(<<"+5511994029275">>).
<<"+11994029275">>

generate_phone

Generates a random valid phone number — of a random type with no argument, or of the given type (mobile or landline).

Returns:

Example:

1> brutils:generate_phone().
<<"38950126454">>
2> brutils:generate_phone(mobile).
<<"59956385883">>
3> brutils:generate_phone(landline).
<<"7529936607">>

Passport

A Brazilian passport number has 2 uppercase letters followed by 6 digits. There is no check digit, so validity says nothing about existence. Note the division of labor: is_valid_passport is strict (case-sensitive, no symbol stripping), while format_passport is lenient — it uppercases and strips symbols before validating, so the same input can fail one and pass the other.

is_valid_passport

Returns whether the given passport number is valid: exactly 2 uppercase letters followed by exactly 6 digits. Lowercase letters and symbols make the input invalid — use format_passport/1 to normalize first.

Args:

Returns:

Example:

1> brutils:is_valid_passport(<<"AB123456">>).
true
2> brutils:is_valid_passport(<<"Ab123456">>).
false
3> brutils:is_valid_passport(<<"AB-123456">>).
false

format_passport

Normalizes and formats a passport number: uppercases ASCII letters, strips the symbols -, . and spaces, then validates the result.

Args:

Returns:

Example:

1> brutils:format_passport(<<"ab-123456">>).
{ok,<<"AB123456">>}
2> brutils:format_passport(<<"111111">>).
{error,invalid}

remove_symbols_passport

Removes the symbols -, . and spaces from a passport string. Only those three characters are removed, and letter case is preserved.

Args:

Returns:

Example:

1> brutils:remove_symbols_passport(<<"Ab -. 123456">>).
<<"Ab123456">>

generate_passport

Generates a random valid passport number: 2 uniform uppercase letters followed by 6 uniform digits.

Returns:

Example:

1> brutils:generate_passport().
<<"AP051847">>
2> brutils:generate_passport().
<<"ZN446187">>

License plate

Two Brazilian plate patterns exist:

Type atomPatternExample
old_formatLLLNNNN — 3 letters + 4 digitsABC1234
mercosulLLLNLNN — 3 letters, digit, letter, 2 digitsABC1D23

Validation ignores letter case and trims surrounding whitespace; formatting and conversion emit uppercase.

is_valid_license_plate

Returns whether the given plate is valid — either pattern for the one-argument form, or a specific one when the type atom is given.

Args:

Returns:

Example:

1> brutils:is_valid_license_plate(<<"ABC1234">>).
true
2> brutils:is_valid_license_plate(<<"abc1d23">>).
true
3> brutils:is_valid_license_plate(<<"ABC-1234">>).
false
4> brutils:is_valid_license_plate(<<"ABC1234">>, mercosul).
false

format_license_plate

Formats a valid plate for display: old-format plates get a dash after the letters, Mercosul plates come out bare — both uppercased.

Args:

Returns:

Example:

1> brutils:format_license_plate(<<"abc1234">>).
{ok,<<"ABC-1234">>}
2> brutils:format_license_plate(<<"abc1e34">>).
{ok,<<"ABC1E34">>}

remove_symbols_license_plate

Removes the dash (-) from a license plate string. Only the dash is removed; anything else is kept unchanged.

Args:

Returns:

Example:

1> brutils:remove_symbols_license_plate(<<"ABC-123">>).
<<"ABC123">>

convert_license_plate_to_mercosul

Converts an old-format plate to the Mercosul pattern by replacing the digit at the fifth position with a letter (0A, 1B, ... 9J). An already-Mercosul plate yields an error, not a no-op.

Args:

Returns:

Example:

1> brutils:convert_license_plate_to_mercosul(<<"ABC4567">>).
{ok,<<"ABC4F67">>}
2> brutils:convert_license_plate_to_mercosul(<<"ABC1D23">>).
{error,invalid}

get_format_license_plate

Detects the pattern of a license plate, returning the type atom (old_format for LLLNNNN, mercosul for LLLNLNN) — the result can be fed straight back into is_valid_license_plate/2.

Args:

Returns:

Example:

1> brutils:get_format_license_plate(<<"abc1234">>).
{ok,old_format}
2> brutils:get_format_license_plate(<<"ABC1D23">>).
{ok,mercosul}

generate_license_plate

Generates a random valid plate — Mercosul with no argument, or in the given pattern (<<"LLLNNNN">> or <<"LLLNLNN">>, case insensitive).

Returns:

Example:

1> brutils:generate_license_plate().
{ok,<<"WMF1O31">>}
2> brutils:generate_license_plate(<<"LLLNNNN">>).
{ok,<<"BFX5517">>}

Voter ID

A Brazilian voter id (título de eleitor) is read from the right:

FieldDigitsPosition
sequential number8 (or 9 for some SP/MG titles)leading
federative union2before the check digits
check digits2last

Titles normally have 12 digits; São Paulo and Minas Gerais titles may have 13 (an extra sequential digit that the checksum ignores). Federative-union codes run 01 (SP) through 27 (TO), with 28 (ZZ) for titles issued abroad.

is_valid_voter_id

Returns whether the given voter id is valid: correct length for its federative union, code in range, and both verifying check digits matching. This function does not verify the existence of the title; it only validates the format of the string.

Args:

Returns:

Example:

1> brutils:is_valid_voter_id(<<"690847092828">>).
true
2> brutils:is_valid_voter_id(<<"690847092820">>).
false
3> brutils:is_valid_voter_id(<<"3476353100183">>).
true

format_voter_id

Formats a valid 12-digit voter id for display with visual spacing (NNNN NNNN NN NN). Valid 13-digit SP/MG titles yield {error, invalid}: the display mask has no slot for their extra digit, so they are refused rather than silently truncated.

Args:

Returns:

Example:

1> brutils:format_voter_id(<<"690847092828">>).
{ok,<<"6908 4709 28 28">>}
2> brutils:format_voter_id(<<"3476353100183">>).
{error,invalid}

generate_voter_id

Generates a random valid 12-digit voter id — for a title issued abroad (ZZ) with no argument, or for the given federative union (two-letter code, case insensitive).

Returns:

Example:

1> brutils:generate_voter_id().
{ok,<<"469000172810">>}
2> brutils:generate_voter_id(<<"sp">>).
{ok,<<"569431460183">>}
3> brutils:generate_voter_id(<<"XX">>).
{error,invalid}

Author

Camilo Cunha de Azevedo camilotk@gmail.com