Vehicle Identification Number (VIN) Regex
Validates that a string is a 17-character Vehicle Identification Number using only the characters the VIN standard allows, excluding the letters I, O, and Q to avoid confusion with 1 and 0.
Regex Pattern
^[A-HJ-NPR-Z0-9]{17}$Pattern Breakdown
Hover over a token to see what it does.
| Token | Meaning |
|---|---|
| ^ | Anchors the match to the start of the string |
| [A-H | Allows letters A through H |
| J-N | Allows letters J through N, skipping the excluded letter I |
| PR-Z0-9] | Allows P, then R through Z (skipping the excluded letters O and Q), plus all digits 0-9 |
| {17} | Exactly 17 characters total, the fixed length mandated by ISO 3779 |
| $ | Anchors the match to the end of the string |
Detailed Explanation
What it does
This pattern checks that a string is exactly 17 characters long and made up only of uppercase letters and digits allowed in a VIN, explicitly excluding I, O, and Q because they are too easily confused with 1 and 0 when handwritten or printed.
Why it works
The VIN standard (ISO 3779, adopted by NHTSA and manufacturers worldwide) fixes the length at 17 and forbids I, O, and Q by specification, so a single character class built by removing those three letters from A-Z, combined with an exact `{17}` count, captures the full allowed alphabet and length in one pass.
Common use cases
- Validating VIN input fields on vehicle registration, insurance quote, or dealership forms
- Sanity-checking VINs scanned via barcode or OCR before a decode API lookup
- Filtering bulk vehicle inventory imports for structurally invalid VINs
- Client-side format checks before calling a VIN decoder service (e.g. NHTSA vPIC API)
Edge cases
- A VIN containing 'I', 'O', or 'Q' is correctly rejected even though those look superficially like valid letters
- Pre-1981 vehicles may have non-standard VIN lengths or formats that this modern 17-character pattern will reject
- This pattern is case-sensitive; lowercase VINs like '1hgcm82633a004352' fail unless the input is uppercased first or an 'i' flag is added
- A VIN passing this format check can still fail the official check-digit (position 9) validation used in North America
Limitations
- Does not verify the position-9 check digit that North American VINs use to detect transcription errors
- Does not confirm the VIN was actually assigned to a real, manufactured vehicle
- Cannot decode or validate the embedded manufacturer, model, or plant codes without a separate lookup
- Pre-1981 VINs with variable length and format are out of scope for this modern fixed-length pattern
Interactive Tester
Edit the pattern or text below — matching runs live in your browser.
Test Cases
Editable — add your own inputs to see if they pass.
| Input | Expected | Result | |
|---|---|---|---|
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass |
Language Variants
Production-ready examples in 12 languages.
const vinRegex = /^[A-HJ-NPR-Z0-9]{17}$/;
console.log(vinRegex.test('1HGCM82633A004352')); // trueCommon Mistakes
Using a plain [A-Z0-9]{17} class and forgetting to exclude I, O, and Q
Fix: Build the character class explicitly as [A-HJ-NPR-Z0-9] to match the real VIN standard
Treating a format-valid VIN as fully verified
Fix: Also validate the position-9 check digit and/or decode the VIN through NHTSA's vPIC API for full confidence
Rejecting lowercase VINs from OCR or barcode scans without normalizing case first
Fix: Uppercase the scanned input before validation, or add the case-insensitive flag if lowercase VINs are expected
Performance Notes
- A single fixed-length character class with {17} is O(n) with no backtracking possibility
- Anchoring the full string prevents accidental partial matches inside longer text blobs
- For batch VIN validation over large datasets, reuse one compiled regex instance rather than recompiling per row
Browser Compatibility
| Engine | Supported | Notes |
|---|---|---|
| Chrome | Yes | — |
| Firefox | Yes | — |
| Safari | Yes | — |
| Edge | Yes | — |
| Node.js | Yes | — |