The National Provider Identifier, issued by CMS to US healthcare providers. Ten digits, and the check digit is a standard Luhn, computed after prepending the fixed prefix 80840. That prefix is the part implementations miss, and without it every valid NPI fails.
public static bool IsNpiValid(string npi)
{
var digits = new string(npi.Where(char.IsDigit).ToArray());
if (digits.Length != 10) return false;
// CMS specifies Luhn over the NPI prefixed with 80840.
return IsLuhnValid("80840" + digits);
}Known-valid test values: 1993999998, 1234567893.
Appendix A carries the rest: Social Security numbers, EINs, ITINs, Medicare Beneficiary Identifiers, IBANs for international customers, and the false-positive characteristics of each.
Look back at the Chapter 4 table, at the CoNLL-2002 column. Regex scored 0.000. Not low. Zero.
That dataset is newspaper text annotated for person names and locations. There is no pattern for a name. There is no checksum for "Springfield". The entire category of unstructured personal data, which is most personal data, is invisible to this layer.
So the honest summary of deterministic detection is a narrow instrument with excellent precision:
| Entity | Deterministic? | Confidence |
|---|---|---|
| Payment card | Yes, Luhn | Very high |
| ABA routing number | Yes, weighted mod-10 | Very high |
| NPI | Yes, Luhn with 80840 prefix | Very high |
| IBAN | Yes, mod-97 | Very high |
| SSN, EIN, ITIN | Range rules only | Medium, needs context |
| Email address | Yes, RFC pattern | High |
| IP address | Yes | High, but often not personal data in context |
| Phone number | Partly | Medium, format varies wildly |
| ZIP code | Partly | Medium, collides with other codes |
| Person name | No | None |
| Address | No | None |
| Free-text disclosure | No | None |
The bottom three rows are why Chapter 6 exists.
The gap is structural rather than a matter of effort. A checksum works because someone designed the identifier to be machine-verifiable. Nobody designed names. There is no length a name must be, no character set it must use, no rule distinguishing "Brook" the person from "brook" the watercourse, and no way to tell that "Mercedes" is a colleague rather than a car without reading the sentence. The same applies to addresses, to dates that are sometimes dates of birth, and to the sentence where a customer volunteers a medical condition.
That is the boundary. Everything with a designed structure belongs to this layer and belongs to it completely. Everything a human wrote in their own words belongs to a model, with the accuracy that Chapter 4 established, which is worse than you would like and better than nothing.
Do not tune these for recall. The value of this layer is that when it fires, it is right. If you loosen the card pattern to catch cards written with unusual separators, you start matching order references, and every false positive damages a downstream result while adding nothing you can rely on. Let this layer be precise and let the model layer chase recall.
Validators drift. Identifier schemes change. Countries add digits, reassign ranges, introduce new formats. A validator written in 2021 against a scheme revised in 2025 fails silently, returning false for legitimate identifiers, which reads as "no PII found". Put a dated comment on every validator naming the scheme version, and add a golden test with known-valid examples, so a scheme change fails a test rather than failing open in production.
That second warning generalises into a principle for the whole book: a detection component that fails should fail loudly, because a detector that returns nothing looks exactly like clean input.
You now have a fast, precise layer that finds structured identifiers and is blind to names, addresses, and everything a person typed in their own words. That is the majority of the problem, and closing it means a model. There are three ways to get one into a .NET application, and they differ in the one dimension this book cares about most.
80840 + NPI — CMS, Requirements for National Provider Identifier (NPI) and NPI Check Digit: https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf · worked example: https://www.johndcook.com/blog/2024/06/26/npi-number/Every validator in this chapter and in Appendix A was executed against the stated known-valid test values before publication. The argument that this layer's value is precision rather than recall is the author's, supported by the 0.000 regex score on CoNLL-2002 in the Chapter 4 table.
Download the full PDF for free?
Free download — no account required