Supported Identifiers
phileas-dotnet ships with a comprehensive set of built-in PII identifier types — pattern-based detectors, dictionary-backed name/location detectors, configurable custom dictionaries, custom regex identifiers, section detectors, and an AI-powered PhEye filter. Each type is enabled by setting the corresponding property on the Identifiers object inside a Policy.
Quick Reference
Pattern-based identifiers
| Property Name | JSON Key | Description |
|---|---|---|
Age |
age |
Numeric age expressions (e.g. "42 years old") |
BankRoutingNumber |
bankRoutingNumber |
US ABA bank routing numbers |
BitcoinAddress |
bitcoinAddress |
Bitcoin wallet addresses |
CreditCard |
creditCard |
Credit and debit card numbers |
Currency |
currency |
Currency amounts (e.g. "$1,234.56") |
Date |
date |
Calendar dates in common formats |
DriversLicense |
driversLicense |
US driver's license numbers |
Ein |
ein |
US Employer Identification Numbers and TINs (NN-NNNNNNN) |
EmailAddress |
emailAddress |
Email addresses |
IbanCode |
ibanCode |
International Bank Account Numbers |
IpAddress |
ipAddress |
IPv4 and IPv6 addresses |
MacAddress |
macAddress |
Network MAC addresses |
PassportNumber |
passportNumber |
Passport numbers |
PhoneNumber |
phoneNumber |
US and international phone numbers |
PhoneNumberExtension |
phoneNumberExtension |
Phone number extensions (e.g. "ext. 123") |
Ssn |
ssn |
US Social Security Numbers (NNN-NN-NNNN) |
StateAbbreviation |
stateAbbreviation |
Two-letter US state codes |
StreetAddress |
streetAddress |
US street addresses |
TrackingNumber |
trackingNumber |
Shipping/parcel tracking numbers |
Url |
url |
HTTP/HTTPS URLs |
Vin |
vin |
Vehicle Identification Numbers |
ZipCode |
zipCode |
US ZIP codes (5-digit and ZIP+4) |
Dictionary-backed name & location identifiers
| Property Name | JSON Key | Description |
|---|---|---|
FirstName |
firstName |
Common first names |
Surname |
surname |
Common surnames |
City |
city |
City names |
County |
county |
County names |
State |
state |
US state names |
Hospital |
hospital |
Hospital names |
Custom & AI identifiers
| Property Name | JSON Key | Description |
|---|---|---|
CustomDictionaries |
dictionaries |
Custom term lists with classification and sensitivity-based fuzzy matching |
CustomIdentifiers |
identifiers |
Custom regex identifiers |
Sections |
sections |
Spans of text delimited by a start and end pattern |
PhEyes |
pheyes |
AI-powered NER via a remote PhEye service |
Common Configuration
Every identifier type inherits from AbstractPolicyFilter:
public abstract class AbstractPolicyFilter
{
public bool Enabled { get; set; } = true;
public List<string>? Ignored { get; set; }
public List<string>? IgnoredFiles { get; set; }
public List<IgnoredPattern>? IgnoredPatterns { get; set; }
public int WindowSize { get; set; } // 0 = use the policy/global default
public int Priority { get; set; }
}
| Property | JSON key | Default | Description |
|---|---|---|---|
Enabled |
enabled |
true |
Whether the filter is active. Set it to false and the filter is not built, so it detects nothing and costs nothing. Each entry of a list-valued identifier (dictionaries, identifiers, sections, pheyes) carries its own setting. |
Id |
id |
none | Optional label for this filter, so it can be named in logs and diagnostics. Carries no PII and has no effect on detection or redaction. |
Ignored |
ignored |
null |
Exact values that should not be redacted. |
IgnoredFiles |
ignoredFiles |
null |
Files whose lines provide additional ignored terms. |
IgnoredPatterns |
ignoredPatterns |
null |
Regex patterns whose matches are not redacted. |
WindowSize |
windowSize |
0 |
Context words on each side of a match; 0 uses the default (5). |
Priority |
priority |
0 |
Higher-priority filter spans win when spans overlap. |
In addition, each identifier exposes a Strategies list that lets you override the default REDACT behaviour. See Filter Strategies for all available strategies.
Identifier Details
Age
Detects age expressions in the forms below.
| Written form | Example |
|---|---|
| A number with its unit | 42 years old, 42-year-old, 30 yo, 3.5 yrs, 22 y/o |
An age or aged keyword |
age 25, aged 65, Age: 47, Age = 47, Age - 47, Age:47 |
A keyword may be separated from its value by :, = or -, with or without surrounding
whitespace, or by whitespace alone, and that whitespace may include a line break, so a label on one
line with its value on the next is detected. A word merely ending in "age", such as coverage: 47,
is not a keyword.
A number following a keyword is read as an age only when it is between 0 and 125, so Bronze Age
1200 and form AGE 2024 are not detected. A zero-padded value, as a fixed-width record writes it
(AGE 047), still reads. The bound applies only to the keyword forms: a number
carrying its own unit, as in 1200 years old, is what makes that form an age and is not
plausibility-checked.
Identifiers = new Identifiers { Age = new Age() }
"identifiers": { "age": {} }
Bank Routing Number
Detects 9-digit ABA routing numbers.
Identifiers = new Identifiers { BankRoutingNumber = new BankRoutingNumber() }
Bitcoin Address
Detects legacy (P2PKH/P2SH) and SegWit Bitcoin wallet addresses.
Identifiers = new Identifiers { BitcoinAddress = new BitcoinAddress() }
Credit Card
Detects credit and debit card numbers including Visa, Mastercard (both the 51-55 and 2221-2720
ranges), American Express, Diners Club, Discover, JCB, and UnionPay.
Detection happens in two stages. The pattern matches any run of 13 to 16 digits, with spaces or
hyphens allowed between them, and the issuer prefix is then checked along with the Luhn checksum as
part of OnlyValidCreditCardNumbers. Keeping issuer prefixes out of the pattern is deliberate: when
they were in it, a card whose range was not listed went undetected rather than merely unvalidated,
which is the worse way for a redaction filter to fail.
A number is detected whatever grouping it is written in, so an American Express printed
NNNN NNNNNN NNNNN is recognised as readily as a card grouped four by four. Numbers shorter than 13
or longer than 16 digits are outside the window, which excludes the 19-digit forms some issuers use.
The consequence is that OnlyValidCreditCardNumbers carries more weight than its name suggests. With
it enabled, which is the default, only issuer-shaped numbers passing the checksum are redacted. With
it disabled, every run of 13 to 16 digits is redacted, including order numbers and timestamps.
Setting OnlyWordBoundaries to false also costs throughput. The pattern then has to be tried at
every offset inside a run of digits rather than only where one begins, so a document containing long
unbroken digit sequences takes substantially longer to filter: 50,000 contiguous digits takes seconds
rather than milliseconds. The per-pattern regex budget does not bound this, because it limits a
single match rather than the total time spent on a document. The default is unaffected.
Identifiers = new Identifiers { CreditCard = new CreditCard() }
| Property | JSON key | Default | Description |
|---|---|---|---|
OnlyValidCreditCardNumbers |
onlyValidCreditCardNumbers |
true |
Keep only numbers that carry a known issuer prefix and pass the Luhn checksum. Disabling it keeps every run of 13 to 16 digits. |
OnlyWordBoundaries |
onlyWordBoundaries |
true |
Require the number to sit on a word boundary. Set to false to find a number embedded in a longer token, at the cost of precision and throughput. |
IgnoreWhenInUnixTimestamp |
ignoreWhenInUnixTimestamp |
false |
Drop digit runs shaped like a thirteen-digit Unix timestamp in epoch milliseconds. Relevant mainly with OnlyValidCreditCardNumbers set to false, where any digit run of the right length is detected. |
Currency
Detects currency amounts with a symbol or ISO code prefix (e.g. $1,234.56, €99.00).
Identifiers = new Identifiers { Currency = new Currency() }
Date
Detects dates in common written and numeric forms.
| Written form | Example |
|---|---|
| Month name first | January 15, 1990, January 15 1990, Jan 15, 1990, Jan. 15, 1990 |
| Day first, month name | 15 January 1990, 15 Jan 1990, 15-Jan-1990, 15/Jan/1990, 15-January-1990 |
| Month first, numeric | 01/15/1990, 01-15-1990, 01.15.1990, and the same with a two-digit year |
| Day first, numeric | 15/01/1990, 15-01-1990, 15.01.1990, and the same with a two-digit year |
| Year first, numeric | 1990-01-15, 1990/01/15, 1990.01.15 |
| ISO 8601 timestamp | 2024-06-01T09:30:00Z (the date part is the span; the time is left alone) |
A day and a month name may be separated by a space, -, / or ., and both separators in the date
must be the same character. A year-first date takes a zero-padded month and day, as ISO 8601 requires,
so a version string such as 2020.1.5 is not read as a date. A date run together with a word, such as
1990-01-15x, is not detected either; the only text allowed against the end of a date is the time of
an ISO 8601 timestamp.
Identifiers = new Identifiers { Date = new Date() }
| Property | JSON key | Default | Description |
|---|---|---|---|
OnlyValidDates |
onlyValidDates |
false |
When true, numeric dates that are not real calendar dates (e.g. 02-31-2019) are not redacted. Month-name dates are always treated as valid. |
Identifiers = new Identifiers
{
Date = new Date { OnlyValidDates = true }
}
The date strategies list uses the JSON key
dateFilterStrategies. TheSHIFT,TRUNCATE_TO_YEARandRELATIVEstrategies (see Filter Strategies) are specific to the Date filter. Each acts on every form above, using the format the matching pattern recorded, and falls back toREDACTfor a token that is not a real calendar date.
Dictionary
Detects user-supplied terms in the input text. A policy can contain any number of dictionaries, each
with an optional classification and a list of terms. Matching is case-insensitive and whole-word,
and every occurrence of a term is detected, including repeats.
Identifiers = new Identifiers
{
CustomDictionaries = new List<CustomDictionary>
{
new CustomDictionary
{
Classification = "medical-conditions",
Terms = new List<string> { "diabetes", "hypertension", "asthma" }
}
}
}
"identifiers": {
"dictionaries": [
{ "classification": "conditions", "terms": ["diabetes", "hypertension"] },
{ "classification": "medications", "terms": ["metformin", "lisinopril"] }
]
}
| Property | JSON key | Default | Description |
|---|---|---|---|
Classification |
classification |
none | Label reported on each span this dictionary produces |
Terms |
terms |
none | The terms to detect |
Files |
files |
none | Files of additional terms, one per line |
Fuzzy |
fuzzy |
false |
Enable near-match detection |
Sensitivity |
sensitivity |
"off" |
How near a match may be: "off", "high", "medium", "low", "auto" |
Capitalized |
capitalized |
false |
Require a match to start with a capital letter |
Strategies |
customFilterStrategies |
none | Filter strategies for this dictionary |
Fuzzy matching
With fuzzy: true, a term is also detected when the text is within a Levenshtein distance of it.
sensitivity sets how far: higher sensitivity means a stricter match.
sensitivity |
Edit distance accepted |
|---|---|
"off" or "high" |
0 (exact only) |
"medium" |
1 |
"low" |
2 |
A near match is detected whether or not the same term also appears exactly elsewhere in the document, so a name written correctly once and misspelled once has both redacted. Each occurrence is reported once, and a span's text is the document's, not the dictionary's spelling of it, which is what a filter strategy operates on.
new CustomDictionary
{
Classification = "medical-conditions",
Terms = new List<string> { "diabetes", "hypertension" },
Fuzzy = true,
Sensitivity = "medium"
}
The deprecated dictionary key
This port also accepted identifiers.dictionary, a .NET-only spelling with name instead of
classification and level instead of sensitivity. The redaction policy schema declares only
dictionaries and rejects keys it does not define, so a policy using it did not validate.
It is still read, and its entries are folded into dictionaries, so an existing policy keeps
redacting. It is never written back: a policy that goes in with dictionary comes out with
dictionaries. Two things change when it is folded:
levelcounted upward ("low"accepted 1 edit,"medium"2,"high"3) whilesensitivitycounts downward, so the mapping goes by the distance each accepts:level: "low"becomessensitivity: "medium", andlevel: "medium"becomessensitivity: "low". Nothing accepts 3 edits, solevel: "high"also becomessensitivity: "low"and stops matching at a distance of 3.- Spans are reported as
custom-dictionaryrather thandictionary, so the default redaction label becomes{{{REDACTED-custom-dictionary}}}.
Driver's License
Detects US state driver's license number formats.
Identifiers = new Identifiers { DriversLicense = new DriversLicense() }
EIN
Detects US Employer Identification Numbers (federal tax IDs) in the NN-NNNNNNN format (two digits, a hyphen, seven digits). The hyphen position distinguishes an EIN from an SSN (NNN-NN-NNNN); a bare nine-digit run is left to the SSN filter and span disambiguation rather than claimed as an EIN.
Identifiers = new Identifiers { Ein = new Ein() }
Relationship to the SSN identifier
NN-NNNNNNN is the US taxpayer identification number (TIN) format assigned to employers, and it is
detected here, not by the SSN identifier. The hyphen position is the whole distinction: after
the second digit for a TIN or EIN, after the third and fifth for an SSN. A value in this format is
reported as ein and never as ssn, so a policy that enables ssn alone does not detect it; enable
ein as well.
Accepted separators
The hyphen is required (a bare nine-digit run is left to the SSN identifier), and the same separators the SSN identifier accepts are accepted here:
- The ASCII hyphen-minus, or any of its substitutes: the soft hyphen (U+00AD), the dashes U+2010
through U+2015 (which include the non-breaking hyphen U+2011), the minus sign (U+2212), and the
small and fullwidth hyphen-minus forms (U+FE58, U+FE63, U+FF0D). The hyphen may be followed by
horizontal whitespace, so
12- 3456789is detected. - A hyphen followed by a line break, so an identifier wrapped across two lines is detected. Both
\nand\r\ncount as the break, and horizontal whitespace may sit on either side of it, so an indented continuation line works.
The input is not normalized, so span offsets index into the original text and a span covers the complete identifier, line break included.
Intentional exclusions
- Whitespace on its own. Unlike an SSN, an EIN is not detected with a space in place of the hyphen. Whitespace following a hyphen is not limited, as above.
- Non-ASCII digits, including the fullwidth, Arabic-Indic and Devanagari forms.
- A value with a hyphen immediately before or after it, so a fragment straddling two longer
identifiers is not claimed:
45-6789123inside123-45-6789123-45-6789produces no span.
Set onlyValidPrefixes to true to keep only matches whose two-digit prefix is one the IRS currently issues, which reduces false positives on format-valid but non-issued numbers. It defaults to false (match any EIN-formatted value), so a prefix issued after this release is still detected; the strict list is engine-carried and only affects the opt-in mode.
The JSON key for the filter strategies list is einFilterStrategies:
"ein": {
"onlyValidPrefixes": true,
"einFilterStrategies": [
{ "strategy": "REDACT" }
]
}
Email Address
Detects RFC-compliant email addresses.
Identifiers = new Identifiers { EmailAddress = new EmailAddress() }
// Whitelist a specific address
Identifiers = new Identifiers
{
EmailAddress = new EmailAddress
{
Ignored = new List<string> { "no-reply@example.com" }
}
}
| Property | JSON key | Default | Description |
|---|---|---|---|
OnlyStrictMatches |
onlyStrictMatches |
true |
Use the RFC-conformant local part, which accepts the specials the RFC permits (!#$%&'*+/=?^_``{|}~). Set tofalse` for a local part of word characters, dots and dashes only. "Strict" means strictly conformant, so it matches more, not less. |
OnlyValidTLDs |
onlyValidTLDs |
false |
Keep only addresses whose top-level domain is in the bundled IANA list. The list is a point-in-time snapshot, so a newly delegated TLD is rejected until it is refreshed. |
IBAN Code
Detects International Bank Account Numbers in standard format (e.g. GB29 NWBK 6016 1331 9268 19).
Identifiers = new Identifiers { IbanCode = new IbanCode() }
| Property | JSON key | Default | Description |
|---|---|---|---|
OnlyValidIBANCodes |
onlyValidIBANCodes |
true |
Keep only codes that pass the MOD-97-10 checksum. |
AllowSpaces |
allowSpaces |
true |
Also detect a code written in the four-character groups banks print. |
IP Address
Detects IPv4 addresses (e.g. 192.168.1.1) and IPv6 addresses in every written form: expanded
(2001:0db8:85a3:0000:0000:8a2e:0370:7334), compressed (2001:db8::1, ::1, 2001:db8::),
IPv4-mapped (::ffff:192.0.2.128), and link-local with a zone identifier (fe80::1%eth0).
An IPv4 address with a letter or underscore immediately against it, such as the 1.2.3.4 of
v1.2.3.4, is still detected and still redacted, but at a lower confidence (0.70 rather than 0.95),
because it is as likely to be a version string or an identifier. Span disambiguation weighs that
confidence when another filter claims the same text. An address delimited by punctuation, such as
build-10.0.0.1-rc, is cleanly bounded and keeps the higher confidence.
A bare :: on its own is not treated as an address. It is the unspecified address, but accepting it
meant every :: in prose or code became a span, so std::vector and Foo::Bar were reported as IP
addresses. A match also cannot begin or end partway through a token, which keeps an address from
being reported as a fragment of one.
Identifiers = new Identifiers { IpAddress = new IpAddress() }
MAC Address
Detects network hardware MAC addresses in XX:XX:XX:XX:XX:XX or XX-XX-XX-XX-XX-XX format.
Identifiers = new Identifiers { MacAddress = new MacAddress() }
Passport Number
Detects US passport numbers.
Identifiers = new Identifiers { PassportNumber = new PassportNumber() }
PhEye
Detects named entities using AI-powered NLP by connecting to a remote PhEye NER service.
Identifiers = new Identifiers
{
PhEyes = new List<PhEye>
{
new PhEye
{
PhEyeConfiguration = new PhEyeConfiguration
{
Endpoint = "http://localhost:8080",
BearerToken = "your-api-token", // Optional
Timeout = 30,
Labels = new List<string> { "PERSON", "ORG", "LOC" }
}
}
}
}
JSON configuration:
"identifiers": {
"pheyes": [
{
"phEyeConfiguration": {
"endpoint": "http://localhost:8080",
"bearerToken": "your-api-token",
"timeout": 30,
"labels": ["PERSON", "ORG", "LOC"]
}
}
]
}
The redaction policy schema also declares
identifiers.person, a deprecated alias carrying a single PhEye configuration rather than a list. A policy using it still loads: the entry is folded intopheyes, after any declared there. It is written back aspheyes, so a policy that goes in withpersoncomes out with the canonical key.
Configuration Options:
| Property | Type | Default | Description |
|---|---|---|---|
endpoint |
string |
"http://localhost:8080" |
Base URL of the PhEye service |
bearerToken |
string? |
null |
Bearer token for authentication |
timeout |
int |
30 |
Request timeout in seconds |
labels |
string[] |
["Person"] |
Entity labels to detect |
Detected Entity Types:
- PERSON / PER → Mapped to FilterType.Person
- LOCATION / LOC → Mapped to FilterType.LocationCity
- ORGANIZATION / ORG → Mapped to FilterType.Other
- MISC → Mapped to FilterType.Other
For detailed documentation, see PhEye Filter Usage.
Phone Number
Detects US and international phone numbers in a variety of formats, backed by Google's libphonenumber (the libphonenumber-csharp port). Text is scanned with a default region of US, so North American Numbering Plan numbers ((555) 123-4567, +1 555 123 4567, 555.123.4567) and any +-prefixed international number (+44 20 7946 0958, +33 1 42 68 53 00, +91 98765 43210, +49 30 901820) are detected regardless of region.
Identifiers = new Identifiers { PhoneNumber = new PhoneNumber() }
| Property | JSON key | Default | Description |
|---|---|---|---|
Region |
region |
US |
The region(s), ISO 3166-1 alpha-2, used to interpret numbers written without an international + country code. Numbers with a + prefix are detected regardless of this value. |
To detect national-format numbers from other countries, set one region or several. Each configured region is scanned and the results are merged, with overlapping matches de-duplicated:
Identifiers = new Identifiers
{
PhoneNumber = new PhoneNumber { Region = new List<string> { "US", "GB", "FR" } }
}
In a JSON policy, region takes either a single string or an array of strings:
{
"identifiers": {
"phoneNumber": {
"region": ["US", "GB", "FR"],
"phoneNumberFilterStrategies": [{"strategy": "REDACT"}]
}
}
}
Region codes are matched exactly, so use the uppercase ISO 3166-1 alpha-2 form (GB, not gb). An unrecognized code leaves national-format numbers undetected; only +-prefixed numbers are found.
The
regionproperty requires redaction policy schema 1.2.0.
Phone Number Extension
Detects phone number extensions (e.g. ext. 1234, x1234).
Identifiers = new Identifiers { PhoneNumberExtension = new PhoneNumberExtension() }
SSN
Detects US Social Security Numbers in NNN-NN-NNNN format. The regex excludes invalid ranges (000, 666, and 900 to 999 area codes; 00 group; 0000 serial).
Identifiers = new Identifiers { Ssn = new Ssn() }
Relationship to the EIN identifier
This identifier covers the Social Security Number forms only: NNN-NN-NNNN, the same digits
separated by whitespace, and the bare nine-digit run. It does not detect the NN-NNNNNNN taxpayer
identification number format, where the hyphen falls after the second digit. That shape belongs to
the EIN identifier and is reported as ein.
Accepted separators
The three groups of an identifier may be separated by any of the following:
- Nothing at all, as in
123456789. - One hyphen, optionally followed by horizontal whitespace. Alongside the ASCII hyphen-minus, the soft hyphen (U+00AD), the dashes U+2010 through U+2015 (which include the non-breaking hyphen U+2011), the minus sign (U+2212), and the small and fullwidth hyphen-minus forms (U+FE58, U+FE63, U+FF0D) are all accepted.
- One horizontal whitespace character on its own: a space, a tab, or a non-breaking space, for example.
- A hyphen followed by a line break, so an identifier wrapped across two lines is still detected.
Both
\nand\r\ncount as the break, and horizontal whitespace may sit on either side of it, so an indented continuation line works.
The input is not normalized, so span offsets index into the original text and a span covers the complete identifier, line break included.
A match may not begin or end partway through a run of ASCII letters, digits, or underscores. Other characters, including non-ASCII letters and digits, do not block a match, so an identifier embedded in non-Latin text is still detected.
Intentional exclusions
These forms produce no span, each by design:
- A line break with no hyphen before it. Accepting one would read three unrelated numbers on three lines as a single identifier.
- A line break inside a group of digits, such as
078-05-11with20on the next line. - Non-ASCII digits, including the fullwidth and Arabic-Indic forms.
- More than one whitespace character between two groups that no hyphen separates. Whitespace
following a hyphen is not limited, so
078- 05- 1120is detected. - Whitespace before the hyphen, as in
078 - 05 - 1120.
The JSON key for the filter strategies list is ssnFilterStrategies:
"ssn": {
"ssnFilterStrategies": [
{ "strategy": "MASK" }
]
}
State Abbreviation
Detects two-letter US state abbreviations (e.g. CA, NY, TX).
Identifiers = new Identifiers { StateAbbreviation = new StateAbbreviation() }
Street Address
Detects US street addresses (e.g. 123 Main St, 456 Oak Ave Apt 7).
Identifiers = new Identifiers { StreetAddress = new StreetAddress() }
Tracking Number
Detects parcel tracking numbers from major carriers (UPS, FedEx, USPS, DHL).
Identifiers = new Identifiers { TrackingNumber = new TrackingNumber() }
| Property | JSON key | Default | Description |
|---|---|---|---|
Ups |
ups |
true |
Detect UPS numbers (1Z followed by sixteen characters). |
Fedex |
fedex |
true |
Detect FedEx numbers (twelve to fifteen digits). |
Usps |
usps |
true |
Detect USPS numbers (twenty to twenty-two digits). |
AllowSpaces |
allowSpaces |
false |
Also detect a number written in space-separated groups. |
URL
Detects HTTP, HTTPS and FTP URLs.
A span ends at the last character that belongs to the URL, so a trailing /, & or # is kept.
Punctuation that prose puts after a URL is not, so see http://example.com/page. redacts the URL and
leaves the sentence's period behind. This holds for punctuation outside ASCII too, including the
ideographic full stop and comma, so a URL in Japanese or Chinese text is not extended by the sentence
mark that follows it. Punctuation inside a path is untouched either way, so /a/b.html and ?q=1,2
are matched whole.
Identifiers = new Identifiers { Url = new Url() }
| Property | JSON key | Default | Description |
|---|---|---|---|
RequireHttpWwwPrefix |
requireHttpWwwPrefix |
true |
Require a http://, https:// or www. prefix. Set to false to also detect a bare host such as example.com/page, which is detected at a lower confidence. |
VIN
Detects 17-character Vehicle Identification Numbers.
Identifiers = new Identifiers { Vin = new Vin() }
ZIP Code
Detects 5-digit US ZIP codes and ZIP+4 codes (e.g. 12345, 12345-6789).
Identifiers = new Identifiers { ZipCode = new ZipCode() }
| Property | JSON key | Default | Description |
|---|---|---|---|
RequireDelimiter |
requireDelimiter |
false |
When true, the +4 extension must be dash-separated (12345-6789); an undelimited 9-digit run is not treated as a ZIP+4. |
Validate |
validate |
false |
When true, ZIP codes not present in the bundled census data are not redacted. |
Identifiers = new Identifiers
{
ZipCode = new ZipCode { Validate = true, RequireDelimiter = true }
}
The ZIP code strategies list uses the (singular) JSON key
zipCodeFilterStrategy. Thepopulationfilter condition also uses the bundled census data.
Names and Locations (dictionary-backed)
FirstName, Surname, City, County, State, and Hospital detect entries from bundled reference dictionaries. Each supports fuzzy matching tuned by a sensitivity level and a capitalized flag.
Identifiers = new Identifiers
{
FirstName = new FirstName(),
Surname = new Surname(),
City = new City { Fuzzy = true, Sensitivity = "medium" },
State = new State(),
Hospital = new Hospital()
}
| Property | JSON key | Default | Description |
|---|---|---|---|
Fuzzy |
fuzzy |
false |
Enable fuzzy (near-match) detection. |
Sensitivity |
sensitivity |
"medium" |
Fuzzy sensitivity: "off", "low", "medium", "high", or "auto". |
Capitalized |
capitalized |
false |
Only match terms that are capitalized in the input. |
The strategies list keys are firstNameFilterStrategies, surnameFilterStrategies, cityFilterStrategies, countyFilterStrategies, stateFilterStrategies, and hospitalFilterStrategies respectively.
Custom Regex Identifiers
CustomIdentifiers lets you define your own regex-based identifiers. Each match is classified with the configured classification.
Identifiers = new Identifiers
{
CustomIdentifiers = new List<Identifier>
{
new Identifier
{
Classification = "employee-id",
Pattern = @"\bEMP-\d{6}\b",
CaseSensitive = true,
GroupNumber = 0
}
}
}
| Property | JSON key | Default | Description |
|---|---|---|---|
Pattern |
pattern |
\b[A-Z0-9_-]{6,}\b |
The regular expression to match. |
Classification |
classification |
"custom-identifier" |
Label applied to matches. |
GroupNumber |
groupNumber |
0 |
Capture group used as the matched text (0 = whole match). |
CaseSensitive |
caseSensitive |
true |
Whether the regex is case-sensitive. |
The strategies list key is identifierFilterStrategies. The JSON key for the list itself on Identifiers is identifiers.
Sections
Sections redact everything between a start pattern and an end pattern (inclusive of the markers).
Identifiers = new Identifiers
{
Sections = new List<Section>
{
new Section { StartPattern = "BEGIN PRIVATE", EndPattern = "END PRIVATE" }
}
}
| Property | JSON key | Default | Description |
|---|---|---|---|
StartPattern |
startPattern |
null |
Regex marking the start of the section. |
EndPattern |
endPattern |
null |
Regex marking the end of the section. |
The strategies list key is sectionFilterStrategies. The JSON key for the list itself on Identifiers is sections.
Enabling Multiple Identifiers
Any combination of identifiers can be enabled in a single policy:
var policy = new Policy
{
Name = "comprehensive",
Identifiers = new Identifiers
{
Ssn = new Ssn(),
CreditCard = new CreditCard(),
EmailAddress = new EmailAddress(),
PhoneNumber = new PhoneNumber(),
IpAddress = new IpAddress(),
Url = new Url(),
Date = new Date()
}
};
When spans from different identifier types overlap, the longest span wins; ties are broken by higher confidence, then higher priority, then earlier position. Set a Priority on an identifier to influence the outcome.