Global vehicle registration mark validation for Java & Spring Boot.
RegMark is a small, offline Java library for syntactic and structural validation of vehicle registration marks—also commonly called license plates, licence plates, number plates, or registration plates. It distinguishes a documented format match from uncertainty and from unsupported jurisdictions, and it can search a country set for every plausible format candidate without pretending to identify a vehicle's origin.
VALID_FORMAT means only that the supplied text matches at least one documented rule in the requested issuing jurisdiction. RegMark does not determine whether a government issued the mark, whether it exists or is currently assigned, which vehicle or owner it belongs to, or whether its tax, inspection, insurance, or legal status is valid. Validation performs no network, registry, database, or filesystem lookup.
The rich outcome is deliberately not boolean:
VALID_FORMAT— at least one documented supported rule matched.INVALID_FORMAT— sufficiently complete ordinary-format coverage permits a structural rejection.INDETERMINATE— useful rules exist, but a non-match cannot safely be called invalid.UNSUPPORTED— no rule has met the evidence bar for the known jurisdiction.
matchesKnownFormat(...) is available when an application intentionally wants to collapse the latter three outcomes to false. ValidationResult remains authoritative.
RegMark is version 0.1.0-SNAPSHOT and has not been published to Maven Central. The catalog is a researched pre-release baseline; see the generated coverage report and its explicit limitations before adopting it for a market.
Build and install it locally:
./mvnw verify
./mvnw installPlain Java dependency after local installation:
<dependency>
<groupId>io.github.adbergman.regmark</groupId>
<artifactId>regmark-core</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>Spring Boot dependency after local installation:
<dependency>
<groupId>io.github.adbergman.regmark</groupId>
<artifactId>regmark-spring-boot-starter</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>Do not copy these coordinates into a remote-only build until a release is actually published.
Validate a known country using ISO alpha-2 or alpha-3 input:
RegistrationMarkValidator validator = RegistrationMarkValidator.getDefault();
ValidationResult result = validator.validate("SE", "ABC123");
if (result.status() == ValidationStatus.VALID_FORMAT) {
// A documented Swedish format matched; this is not proof of issuance.
}Validate an exact supported subnational jurisdiction:
ValidationResult result = validator.validate("AU-VIC", "1AA1AA");
result.matchedJurisdictions(); // [AU-VIC]
result.matchedRules(); // immutable rule-match metadata, never raw regexCountry validation aggregates supported subdivisions. For example, validate("AU", mark) considers every implemented Australian state/territory rule and can return more than one matching jurisdiction.
validator.jurisdictions("US") exposes the known issuing jurisdictions and their individual coverage status. A well-formed, cataloged but unsupported issuer such as US-TX returns UNSUPPORTED; a fabricated identifier remains a caller error. Country coverage metadata includes the source IDs that explain each coverage decision, which resolve through validator.sources().
The same string can satisfy several registration systems. Worldwide and regional operations therefore return candidates, never a guessed origin:
MatchResult matches = validator.match(
"ABC123",
ValidationScope.worldwide());
for (CandidateMatch candidate : matches.candidates()) {
System.out.println(candidate.country() + " / " + candidate.jurisdiction());
}Built-in scopes are StandardScopes.WORLDWIDE, StandardScopes.EU, and StandardScopes.NORDICS. Nordics means the official Nordic-cooperation definition—Åland, Denmark, Finland, the Faroe Islands, Greenland, Iceland, Norway, and Sweden—not Scandinavia, the EEA, Europe, or the EU.
Enterprise applications can define their actual supported markets:
ValidationScope supportedMarkets = ValidationScope.countries(
"supported-markets",
Set.of("SE", "NO", "DK", "FI", "DE"));
MatchResult matches = validator.match("ABC123", supportedMarkets);Candidate matching reports the complete, partial, and unsupported coverage composition of the requested scope. It does not assign probabilities or confidence percentages.
The starter uses @AutoConfiguration and backs off when the application provides its own RegistrationMarkValidator bean. No component scanning or configuration properties are introduced.
@Service
class VehicleService {
private final RegistrationMarkValidator registrationMarkValidator;
VehicleService(RegistrationMarkValidator registrationMarkValidator) {
this.registrationMarkValidator = registrationMarkValidator;
}
ValidationResult validateSwedishMark(String mark) {
return registrationMarkValidator.validate("SE", mark);
}
}The starter is compiled against Spring Boot 3.5.16, and the same auto-configuration contract is tested unchanged against 3.5.16, 4.0.7, and 4.1.0. RegMark targets Java 17 bytecode; CI covers JDK 17, 21, and 25. Boot 3.5.16 is the final open-source 3.5 release; 4.0 and 4.1 are the maintained open-source lines at the 2026-08-20 review date.
The bundled catalog contains the 249 assigned ISO 3166-1 entries reviewed on 2026-08-20. Alpha-2 is canonical; alpha-3 is accepted as an alias. GB/GBR are canonical aliases for the United Kingdom; UK is a documented convenience alias and does not create a 250th country. Unknown or malformed identifiers are caller errors rather than fake unsupported countries.
Every canonical entry is explicitly COMPLETE, PARTIAL, or UNSUPPORTED. Issuing structure (NATIONAL, SUBNATIONAL, MIXED, or not yet established) is separate metadata. Exact counts and country-by-country limitations are generated from the runtime catalog in docs/coverage.md.
RegMark applies Unicode NFC, outer trimming, non-expanding Unicode case conversion, and normalization of common typographic dash variants at the boundary. Space and hyphen tolerance is then rule-specific. It never globally removes punctuation, transliterates native scripts, or performs OCR substitutions such as 0 → O. Inputs longer than 64 Unicode code points and malformed surrogate sequences are rejected before rule matching. Patterns are compiled once in an immutable catalog.
Each substantive rule references source metadata including URL, title, organization, authority class, review date, and limitations. Authorities and legislation are preferred; secondary and specialist sources are labeled and never silently upgraded to official evidence. Positive examples are published or transparently source-derived; synthetic data is used for negative boundaries only.
See data sources, rule authoring, and architecture. To correct a rule, follow CONTRIBUTING.md: update the declaration, provenance, positive and negative fixtures, coverage decision, generated documentation, and regression tests together.
The POM is prepared for a future signed Central Portal deployment, but no artifact has been published. Release documentation records the remaining namespace, credential, signing, validation, and manual-publish steps.
RegMark's original code and documentation use the Apache License 2.0; see LICENSE. The bundled deterministic ISO country inventory is derived from Debian iso-codes and remains under LGPL-2.1-or-later. See third-party notices and the license text.