@privacyscrubber/mcp-server 2.3.9 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -11
- package/index.js +881 -79
- package/manifest.json +84 -8
- package/package.json +3 -2
- package/pii-masking-run.js +103 -26
- package/ps-license-manager.cjs +261 -11
- package/ps-license-manager.js +4 -0
- package/ps-pii-engine.cjs +450 -96
- package/ps-pii-engine.js +450 -96
- package/scrubber-core.cjs +31 -25
- package/server.json +27 -4
package/ps-pii-engine.js
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function() {
|
|
11
|
-
if (typeof window !== 'undefined' && window.PrivacyScrubberEngine)
|
|
11
|
+
if (typeof window !== 'undefined' && window.PrivacyScrubberEngine) {
|
|
12
|
+
if (typeof exports !== 'undefined') module.exports = window.PrivacyScrubberEngine;
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
12
15
|
|
|
13
16
|
// --- START DEFAULT RULES ---
|
|
14
17
|
/**
|
|
@@ -21,14 +24,32 @@ let DEVOPS_SECRETS = [
|
|
|
21
24
|
{ name: 'Private Cryptographic Key (PEM Block)', type: 'SECRET', regex: /-----BEGIN (?:RSA |EC |PGP |DSA |OPENSSH |ENCRYPTED )?PRIVATE KEY(?: BLOCK)?-----[\s\S]{10,8192}?-----END (?:RSA |EC |PGP |DSA |OPENSSH |ENCRYPTED )?PRIVATE KEY(?: BLOCK)?-----/g },
|
|
22
25
|
{ name: 'Private Cryptographic Key (Header)', type: 'SECRET', regex: /-----BEGIN (?:RSA |EC |PGP |DSA |OPENSSH |ENCRYPTED )?PRIVATE KEY(?: BLOCK)?-----/g },
|
|
23
26
|
|
|
24
|
-
// Connection URIs & Credentials
|
|
27
|
+
// Connection URIs, Webhooks & Credentials
|
|
28
|
+
{ name: 'Slack / Discord Incoming Webhook URL', type: 'SECRET', regex: /\bhttps:\/\/(?:hooks\.slack\.com\/services\/T[A-Z0-9_]+\/B[A-Z0-9_]+\/[A-Za-z0-9_-]+|(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks\/\d{17,20}\/[A-Za-z0-9_-]{60,70})\b/gi },
|
|
29
|
+
{ name: 'Azure Connection String / SAS Token', type: 'SECRET', regex: /(?:DefaultEndpointsProtocol=https?;AccountName=[^;\s"']+;AccountKey=[A-Za-z0-9+/=]{20,}(?:;EndpointSuffix=[^;\s"']+)?|Endpoint=sb:\/\/[^;\s"']+;SharedAccessKeyName=[^;\s"']+;SharedAccessKey=[A-Za-z0-9+/=]{16,}|\bSharedAccessSignature=sr=[^\s"']+&sig=[A-Za-z0-9%/+=]{16,}|\bAccountKey=[A-Za-z0-9+/=]{40,88}==)/gi },
|
|
25
30
|
{ name: 'Database Connection URI', type: 'SECRET', regex: /\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^\s"']+/gi },
|
|
26
|
-
{ name: 'Embedded Credentials URI', type: 'SECRET', regex: /\b(?:
|
|
31
|
+
{ name: 'Embedded Credentials URI', type: 'SECRET', regex: /\b(?:h(?:tt|xx)ps?|s?f(?:t|x)p|wss?):\/\/[a-zA-Z0-9_.%+-]+:[^\s/@:"']+@[a-zA-Z0-9_.-]+(?:(?:\[\.\]|\(\.\))[a-zA-Z0-9_.-]+)*(?::\d+)?(?:\/[^\s"']*)?/gi },
|
|
32
|
+
{ name: 'Docker Registry Auth / K8s Secret Base64', type: 'SECRET', regex: /(?<=["']?(?:auth|identitytoken|registrytoken|\.dockerconfigjson)["']?\s*:\s*["'])[A-Za-z0-9+/=]{16,}(?=["'])/gi },
|
|
27
33
|
{ name: 'URL Query Parameter Secret', type: 'SECRET', regex: /(?<=[?&](?:api_key|apikey|access_token|client_secret|auth_token|token|secret|password|private_key)=)[^\s"'\x26#)>]{8,}/gi },
|
|
28
|
-
{ name: '
|
|
34
|
+
{ name: 'CLI Credential Flag / Curl User Auth', type: 'SECRET', regex: /(?:\bcurl\b[^\r\n]*?\s(?:-u|--user)\s+["']?[A-Za-z0-9_.+-]+:[^\s"']+|\b(?:--password|--api-key|--apikey|--access-token|--auth-token|--client-secret|--secret-key|--private-key)(?:=|\s+)["']?[^\s"']{6,}["']?)/gi },
|
|
35
|
+
{ name: 'HTTP API Key Header', type: 'SECRET', regex: /\b(?:X-API-Key|X-Amz-Security-Token|X-Functions-Key|X-Shopify-Access-Token|X-Auth-Token|Api-Key)\s*:\s*["']?[A-Za-z0-9_.\-~+/=]{12,}["']?/gi },
|
|
36
|
+
{ name: 'Bearer / Auth Header Token', type: 'SECRET', regex: /(?<=\b(?:Bearer|Token)\s+)[a-zA-Z0-9_\-\.~+/=]{16,}(?![a-zA-Z0-9_\-\.~+/=])/gi },
|
|
37
|
+
{ name: 'HTTP Basic Auth Token', type: 'SECRET', regex: /(?<=\bAuthorization\s*:\s*Basic\s+)[A-Za-z0-9+/=]{8,}(?![A-Za-z0-9+/=])/gi },
|
|
29
38
|
|
|
30
39
|
// Secrets & API Keys
|
|
31
40
|
{ name: 'AWS Credentials', type: 'SECRET', regex: /\b(?:AKIA|ASIA|AGPA|AIDA|AROA|AIPA)[A-Z0-9]{12,28}\b/g },
|
|
41
|
+
{ name: 'Google Cloud / Gemini API Key', type: 'SECRET', regex: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
42
|
+
{ name: 'Anthropic API Key', type: 'SECRET', regex: /\bsk-ant-(?:api\d{2}|admin\d{2}|sid\d{2})-[a-zA-Z0-9_-]{16,128}\b/g },
|
|
43
|
+
{ name: 'HuggingFace / Perplexity API Key', type: 'SECRET', regex: /\b(?:hf_[a-zA-Z0-9]{20,64}|pplx-[a-zA-Z0-9]{24,64})\b/g },
|
|
44
|
+
{ name: 'SendGrid API Key', type: 'SECRET', regex: /\bSG\.[a-zA-Z0-9_-]{16,32}\.[a-zA-Z0-9_-]{32,64}\b/g },
|
|
45
|
+
{ name: 'Postman API Key', type: 'SECRET', regex: /\bPMAK-[a-fA-F0-9]{24}-[a-fA-F0-9]{34}\b/g },
|
|
46
|
+
{ name: 'GitHub Fine-Grained PAT', type: 'SECRET', regex: /\bgithub_pat_[a-zA-Z0-9]{20,30}_[a-zA-Z0-9]{40,80}\b/g },
|
|
47
|
+
{ name: 'Slack Enterprise / Refresh Token', type: 'SECRET', regex: /\bxoxe\.xox[baprs]-\d-[a-zA-Z0-9-]{10,}\b|\bxox[eapbrs]-[a-zA-Z0-9-]{10,}\b/g },
|
|
48
|
+
{ name: 'Telegram Bot API Token', type: 'SECRET', regex: /\b\d{8,10}:AA[A-Za-z0-9_-]{33}\b/g },
|
|
49
|
+
{ name: 'Age Encryption Secret Key', type: 'SECRET', regex: /\bAGE-SECRET-KEY-1[A-Z0-9]{58}\b/g },
|
|
50
|
+
{ name: 'Modern Cloud & AI Platform Key', type: 'SECRET', regex: /\b(?:sbp_[a-fA-F0-9]{40}|dop_v1_[a-fA-F0-9]{64}|doo_v1_[a-fA-F0-9]{64}|dp\.(?:st|pt|ct|sa)\.[a-zA-Z0-9_-]{20,}|lin_api_[a-zA-Z0-9]{32,64}|ntn_[a-zA-Z0-9]{32,64}|secret_[a-zA-Z0-9]{32,64}|gsk_[a-zA-Z0-9]{32,64}|r8_[a-zA-Z0-9]{24,64}|tvly-[a-zA-Z0-9_-]{20,64}|fc-[a-fA-F0-9]{32}|dapi[a-fA-F0-9]{32}(?:-\d)?|re_[a-zA-Z0-9_]{20,64}|pypi-[A-Za-z0-9_-]{16,128}|whsec_[A-Za-z0-9+/=_-]{24,128}|shpat_[a-fA-F0-9]{32}|shpss_[a-fA-F0-9]{32}|shpca_[a-fA-F0-9]{32}|shppa_[a-fA-F0-9]{32}|hvs\.[A-Za-z0-9_-]{24,128}|hvb\.[A-Za-z0-9_-]{24,128}|glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8}|glc_[A-Za-z0-9+/=_-]{20,128}|pscale_tkn_[A-Za-z0-9_.-]{20,64}|pscale_pw_[A-Za-z0-9_.-]{20,64}|pat[A-Za-z0-9]{14}\.[a-fA-F0-9]{64}|pat-(?:na1|eu1)-[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}|sq0atp-[A-Za-z0-9_-]{22,64}|sq0csp-[A-Za-z0-9_-]{32,64}|NRAK-[A-Z0-9]{27}|v1\.0-[a-fA-F0-9]{24}-[a-fA-F0-9]{16,160}|ATATT3xFfGF0[A-Za-z0-9+/=_-]{24,128}|tskey-(?:auth|api|client)-[A-Za-z0-9_-]{20,96}|sntry[su]_[A-Za-z0-9+/=_-]{32,160}|(?:pk|sk)\.eyJ1[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{16,}|key-[a-f0-9]{32}|[a-f0-9]{32}-us\d{1,2}|napi_[a-zA-Z0-9]{32,64}|[a-zA-Z0-9]{14}\.atlasv1\.[a-zA-Z0-9]{50,80})\b/g },
|
|
51
|
+
{ name: 'Twilio Account SID / API Key', type: 'SECRET', regex: /\b(?:AC|SK)[a-fA-F0-9]{32}\b/g },
|
|
52
|
+
{ name: 'Bcrypt / Argon2 Password Hash', type: 'SECRET', regex: /(?<![A-Za-z0-9])(?:\$2[aby]\$\d{2}\$[./A-Za-z0-9=]{20,60}|\$argon2(?:id|i|d)\$[^\s"']{15,120})/g },
|
|
32
53
|
{ name: 'AWS Resource Name (ARN)', type: 'ID', regex: /\barn:(?:aws|aws-cn|aws-us-gov):[a-z0-9-]+:[a-z0-9-]*:(?:\d{12})?:[a-zA-Z0-9-_\/.:*]+\b/gi },
|
|
33
54
|
{ name: 'AWS Account ID', type: 'ID', regex: /(?<=\b(?:accountId|account_id|account-id|AWS\s+Account|Account)\s*[:=]\s*["']?)\d{12}\b/gi },
|
|
34
55
|
{ name: 'GCP Resource / Secret Path', type: 'ID', regex: /\bprojects\/[a-z0-9-]+(?:\/secrets\/[a-zA-Z0-9_.-]+|\/serviceAccounts\/[a-zA-Z0-9_.-]+|\/subscriptions\/[a-zA-Z0-9_.-]+)(?:\/versions\/[a-zA-Z0-9_.-]+)?\b/gi },
|
|
@@ -43,7 +64,7 @@ let DEVOPS_SECRETS = [
|
|
|
43
64
|
{ name: 'Hash / Hex Key (32-64 chars)', type: 'SECRET', regex: /\b[a-fA-F0-9]{32,64}\b/g },
|
|
44
65
|
{ name: 'CVE Identifier', type: 'SECRET', regex: /\bCVE-\d{4}-\d{4,}\b/gi },
|
|
45
66
|
{ name: 'Cryptographic Hash', type: 'SECRET', regex: /\b(?:MD5|SHA1|SHA256)[:\s][a-f0-9]{32,64}\b/gi },
|
|
46
|
-
{ name: 'Database/API Secret', type: 'SECRET', regex: /(?<![?&])\b(?:(?:DB|POSTGRES|REDIS|MYSQL|DATABASE)[-_]?(?:PASSWORD|PASS|SECRET|KEY|PWD|CREDENTIALS?|TOKEN|AUTH)|AWS[-_]?(?:SECRET_ACCESS_KEY|SECRET_KEY|SESSION_TOKEN|SECURITY_TOKEN)|API[-_]?(?:KEY|SECRET|TOKEN|PASS|PASSWORD|AUTH|CREDENTIALS?)|[A-Za-z0-9_]*SECRET[A-Za-z0-9_]*|[A-Za-z0-9_]*PASSWORD[A-Za-z0-9_]*|[A-Za-z0-9_]*PASSWD[A-Za-z0-9_]*|[A-Za-z0-9_]*TOKEN[A-Za-z0-9_]*|ENCRYPTION[-_]KEY)[ \t]*[:=][ \t]*["']?(?:Bearer\s+)?([^\s"'&;\r\n]
|
|
67
|
+
{ name: 'Database/API Secret', type: 'SECRET', regex: /(?<![?&])\b(?:(?:DB|POSTGRES|REDIS|MYSQL|DATABASE)[-_]?(?:PASSWORD|PASS|SECRET|KEY|PWD|CREDENTIALS?|TOKEN|AUTH)|AWS[-_]?(?:SECRET_ACCESS_KEY|SECRET_KEY|SESSION_TOKEN|SECURITY_TOKEN)|API[-_]?(?:KEY|SECRET|TOKEN|PASS|PASSWORD|AUTH|CREDENTIALS?)|[A-Za-z0-9_]*SECRET[A-Za-z0-9_]*|[A-Za-z0-9_]*PASSWORD[A-Za-z0-9_]*|[A-Za-z0-9_]*PASSWD[A-Za-z0-9_]*|[A-Za-z0-9_]*TOKEN[A-Za-z0-9_]*|ENCRYPTION[-_]KEY)[ \t]*[:=][ \t]*["']?(?:Bearer\s+)?([^\s"'&;\r\n,]+?)(?=["'\s&;\r\n,]|$)/gi },
|
|
47
68
|
{ name: 'Proprietary IP / Confidential', type: 'SECRET', regex: /\b(?:CONFIDENTIAL|PROPRIETARY|TRADE SECRET|DO NOT DISTRIBUTE|INTERNAL USE ONLY)\b/gi }
|
|
48
69
|
];
|
|
49
70
|
|
|
@@ -51,6 +72,8 @@ let REGEX_RULES = [
|
|
|
51
72
|
// --- Multi-National PII & National Identifiers (General Profile Base Rules) ---
|
|
52
73
|
// 1. Israel Phone Number (Mobile, Landline & VoIP)
|
|
53
74
|
{ name: 'Israel Phone Number', type: 'PHONE', regex: /(?<!\w)(?:(?:\+972[-.\s]?|0)(?:5[0-9]|[23489]|7[2346789]))[-.\s]?\d{3}[-.\s]?\d{4}\b/g },
|
|
75
|
+
// 1a. Brazil Phone Number (+55 (11) 98765-4321, (11) 98765-4321, (11) 3456-7890)
|
|
76
|
+
{ name: 'Brazil Phone Number', type: 'PHONE', regex: /(?<!\w)(?:(?:\+|00)55[ \t.-]*)?\([1-9]\d\)[ \t.-]*9?\d{4}[ \t.-]*\d{4}\b|(?<!\w)(?:\+|00)55[ \t.-]*[1-9]\d[ \t.-]*9?\d{4}[ \t.-]*\d{4}\b/g },
|
|
54
77
|
// 1b. European Parenthetical Trunk Zero Phone (+31 (0)6..., +49 (0)171..., +33 (0)6..., +44 (0)20..., +34 (0)...)
|
|
55
78
|
{ name: 'European Parenthetical Trunk Zero Phone', type: 'PHONE', regex: /(?<![A-Za-z0-9./_-])(?:\+|00)(?:31|49|33|44|39|34|972)[ \t\xA0]*\(\s*0\s*\)[ \t\xA0]*[1-9](?:[ \t./-]?\d{1,4}){2,5}\b/g },
|
|
56
79
|
// 1c. France Phone Number (5 pairs of 2 digits with dots, spaces, or hyphens: 01.23.45.67.89, 06 12 34 56 78, +33 1 23 45 67 89)
|
|
@@ -64,14 +87,20 @@ let REGEX_RULES = [
|
|
|
64
87
|
// 1g. Spain & Italy Phone Numbers (International & labeled national mobile/landline)
|
|
65
88
|
{ name: 'Spain Phone Number', type: 'PHONE', regex: /(?:(?:\b(?:Tel(?:[ée]fono)?|M[oó]vil|Tlf\.?|Cel\.?)[:\s#=-]+)|(?<!\w)(?:\+|00)34[ \t\xA0]*)([6789]\d{2}[ \t.-]?(?:\d{3}[ \t.-]?\d{3}|\d{2}[ \t.-]?\d{2}[ \t.-]?\d{2}))\b/gi },
|
|
66
89
|
{ name: 'Italy Phone Number', type: 'PHONE', regex: /(?:(?:\b(?:Tel(?:efono)?|Cell(?:ulare)?|Mobile)[:\s#=-]+)|(?<!\w)(?:\+|00)39[ \t\xA0]*)(?:(3\d{2}[ \t.-]?(?:\d{6,7}|\d{3}[ \t.-]?\d{3,4}))|(0\d{1,3}[ \t.-]?\d{6,8}))\b/gi },
|
|
67
|
-
// 2. Israel Teudat Zehut (with Mod 10 Luhn validator)
|
|
68
|
-
{ name: 'Israel National ID (Teudat Zehut)', type: 'ID', validatorType: 'luhn_il', regex: /(?:(
|
|
90
|
+
// 2. Israel Teudat Zehut (with Mod 10 Luhn validator, supporting hyphenated check digit e.g. 01234567-4)
|
|
91
|
+
{ name: 'Israel National ID (Teudat Zehut)', type: 'ID', validatorType: 'luhn_il', regex: /(?:(?:(?<=^|[^\p{L}\p{N}_])(?:תעודת\s+זהות|ת\.?ז\.?|ת["״]ז|מספר\s+זהות|מ\.?ז\.?|Teudat\s+Zehut|TZ)\s*[:#=-]?\s*)|\b(?<!\d))(\d{7,8}-\d|\d{8,9})\b(?!\d)/giu },
|
|
69
92
|
// 3. Israel Company Registration (H.P. / 50-58 prefix with Mod 10 Luhn validator)
|
|
70
|
-
{ name: 'Israel Company Registration (H.P.)', type: 'ID', validatorType: 'luhn_il', regex: /(?:(
|
|
93
|
+
{ name: 'Israel Company Registration (H.P.)', type: 'ID', validatorType: 'luhn_il', regex: /(?:(?:(?<=^|[^\p{L}\p{N}_])(?:ח\.?פ\.?|ח["״]פ|ע\.?ר\.?|ע\.?מ\.?|ע["״]מ|מע["״]מ|תיק\s+מע["״]מ|מספר\s+תאגיד|חברה\s+פרטית|עוסק\s+מורשה)\s*[:#=-]?\s*)|\b(?<!\d))(5[0124568]\d{6}-?\d)\b(?!\d)/giu },
|
|
94
|
+
// 3a0. Israel Vehicle License Plate (7 or 8 digits formatted or labeled)
|
|
95
|
+
{ name: 'Israel Vehicle License Plate', type: 'ID', regex: /(?:(?<=^|[^\p{L}\p{N}_])(?:מספר\s+רכב|מס['’]\s+רכב|לוחית\s+רישוי|מספר\s+רישוי)\s*[:#=-]?\s*)(\d{2}-\d{3}-\d{2}|\d{3}-\d{2}-\d{3}|\d{7,8})\b/giu },
|
|
96
|
+
// 3a. Brazil Individual Tax ID (CPF) & Corporate Tax ID (CNPJ) & Identity Card (RG)
|
|
97
|
+
{ name: 'Brazil Individual Tax ID (CPF)', type: 'ID', validatorType: 'mod11_br_cpf', regex: /(?:(?:\bCPF(?:\s*(?:n[º°o]\.?|número|num\.?|#))?[^\S\r\n]*[:#=-]?[^\S\r\n]*)|(?<!\d))(\d{3}\.\d{3}\.\d{3}-\d{2}|\d{11})\b(?!\d)/gi },
|
|
98
|
+
{ name: 'Brazil Corporate Tax ID (CNPJ)', type: 'ID', validatorType: 'mod11_br_cnpj', regex: /(?:(?:\bCNPJ(?:\s*(?:n[º°o]\.?|número|num\.?|#))?[^\S\r\n]*[:#=-]?[^\S\r\n]*)|(?<!\d))(\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}|\d{14})\b(?!\d)/gi },
|
|
99
|
+
{ name: 'Brazil Identity Card (RG)', type: 'ID', regex: /\bRG(?:\s*(?:n[º°o]\.?|número|#))?[^\S\r\n]*[:#=-]?[^\S\r\n]*(\d{1,2}\.?\d{3}\.?\d{3}-?[0-9Xx])\b/gi },
|
|
71
100
|
// 3b. Israel Domestic Bank Account Details (Bank, Branch, Account tripartite / בנק, סניף, חשבון)
|
|
72
101
|
{ name: 'Israel Domestic Bank Account Details', type: 'FINANCIAL', regex: /(?:^|[^\p{L}\p{N}_])(בנק\s+\d{1,3}[,\s]+סניף\s+\d{1,3}[,\s]+(?:חשבון(?:\s+בנק|\s+מספר|\s+מס['’])?|מספר\s+חשבון)\s+\d{5,9})/giu },
|
|
73
102
|
// 4. Israel Street Address (Hebrew street prefix with prepositions [במבל]?)
|
|
74
|
-
{ name: 'Israel Street Address', type: 'ADDRESS', isContextAddress: true, regex: /(?:^|[^\p{L}\p{N}_])(
|
|
103
|
+
{ name: 'Israel Street Address', type: 'ADDRESS', isContextAddress: true, regex: /(?:^|[^\p{L}\p{N}_])(?:כתובת(?:\s*למשלוח|\s*מגורים)?[:\s#=-]+)?((?:[במבל]?(?:רחוב|רח['’]|שדרות|שד['’]|דרך|סמטת|סמטה|ת\.?ד\.?))\s+[\u0590-\u05FF'’"-]+(?:\s+[\u0590-\u05FF'’"-]+){0,3}\s+\d{1,4}(?:[ \t\xA0]*,?[ \t\xA0]*(?:דירה|כניסה|קומה)\s+\d{1,3})?(?:[ \t\xA0]*,?[ \t\xA0]*[\u0590-\u05FF'’"-]+(?:\s+[\u0590-\u05FF'’"-]+){0,2})?(?:[ \t\xA0]+(?:\d{7}|\d{5}))?)/giu },
|
|
75
104
|
// 4b. Israel Tabu Cadastre (Block & Parcel / גוש וחלקה)
|
|
76
105
|
{ name: 'Israel Tabu Cadastre', type: 'ADDRESS', regex: /(?:^|[^\p{L}\p{N}_])((?:רישום(?:\\s+זכויות)?(?:\\s+בטאבו)?[:\\s#=-]*)?גוש\s+\d{3,6}\s+חלקה\s+\d{1,4}(?:\s+תת[- ]חלקה\s+\d{1,3})?)/giu },
|
|
77
106
|
// 5a. Hebrew Professional Title Name (עו"ד, רו"ח, ד"ר, פרופ', כב' השופט, רשם, etc. with verb-guard)
|
|
@@ -79,9 +108,11 @@ let REGEX_RULES = [
|
|
|
79
108
|
// 5b. Hebrew Contextual Role Name (תובע, נתבע, מבקש, משיב, נאמן, עובד, לקוח, etc.)
|
|
80
109
|
{ name: 'Hebrew Contextual Role Name', type: 'NAME', isContextName: true, regex: /(?:^|[^\p{L}\p{N}_])(?:שם\s+התובע|שם\s+התובעת|התובע|התובעת|שם\s+הנתבע|שם\s+הנתבעת|הנתבע|הנתבעת|המבקש|המבקשת|המשיב|המשיבה|הנאמן|הנאמנת|המערער|המערערת|החייב|החייבת|הזוכה|העובד|העובדת|עובד|עובדת|המעסיק|המעסיקה|מעסיק|המבוטח|המבוטחת|מבוטח|החולה|המטופל|המטופלת|הלקוח|הלקוחה|איש\s+קשר|הרוכש|הרוכשת|המוכר|המוכרת|השוכר|השוכרת|המשכיר|המשכירה|הערב|הערבה|מורשה\s+חתימה|שם|שם\s+מלא|מאת|לכבוד|השם\s+שלי|קוראים\s+לי)[ \t\xA0]*[:#=-][ \t\xA0]*((?!(?:(?:[ובלמ]?(?:עו"ד|עוה"ד|רו"ח|ד"ר|פרופ'|עורך\s+דין|עורכת\s+דין|רואה\s+חשבון|רואת\s+חשבון|השופט|השופטת|כב'[\s\xA0]+השופט|כב'[\s\xA0]+השופטת|רשם|רשמת|יועץ\s+מס|יועצת\s+מס|מר|גב'|גברת))|הגיש|הגישה|הגישו|אישר|אישרה|אישרו|חתם|חתמה|חתמו|הודיע|הודיעה|הודיעו|טוען|טוענת|טוענים|מייצג|מייצגת|מייצגים|פנה|פנתה|פנו|קבע|קבעה|קבעו|כתב|כתבה|כתבו|נכח|נכחה|נכחו|הורה|הורתה|הורו|סבור|סבורה|סבורים|מבקש|מבקשת|מבקשים|דורש|דורשת|דורשים|העיד|העידה|העידו|הסביר|הסבירה|הסבירו|נפטר|נפטרה|נפטרו|נולד|נולדה|נולדו|הופיע|הופיעה|הופיעו|בדק|בדקה|בדקו|טיפל|טיפלה|טיפלו|רשם|רשמה|רשמו|מסר|מסרה|מסרו|אמר|אמרה|אמרו|אתמול|היום|מחר|ביום|במשרד|בבית|בפני|בעניין|בע"מ|לפני|נגד|בדבר|מטעם)[\s\xA0.,;:!?]|$)\p{sc=Hebrew}+(?:['’]\p{sc=Hebrew}+)?(?:-\p{sc=Hebrew}+)?(?:[ \t\xA0]+(?:בן|בר|בת)[ \t\xA0]+\p{sc=Hebrew}+(?:['’]\p{sc=Hebrew}+)?(?:-\p{sc=Hebrew}+)?|[ \t\xA0]+(?!(?:(?:[ובלמ]?(?:עו"ד|עוה"ד|רו"ח|ד"ר|פרופ'|עורך\s+דין|עורכת\s+דין|רואה\s+חשבון|רואת\s+חשבון|השופט|השופטת|כב'[\s\xA0]+השופט|כב'[\s\xA0]+השופטת|רשם|רשמת|יועץ\s+מס|יועצת\s+מס|מר|גב'|גברת))|הגיש|הגישה|הגישו|אישר|אישרה|אישרו|חתם|חתמה|חתמו|הודיע|הודיעה|הודיעו|טוען|טוענת|טוענים|מייצג|מייצגת|מייצגים|פנה|פנתה|פנו|קבע|קבעה|קבעו|כתב|כתבה|כתבו|נכח|נכחה|נכחו|הורה|הורתה|הורו|סבור|סבורה|סבורים|מבקש|מבקשת|מבקשים|דורש|דורשת|דורשים|העיד|העידה|העידו|הסביר|הסבירה|הסבירו|נפטר|נפטרה|נפטרו|נולד|נולדה|נולדו|הופיע|הופיעה|הופיעו|בדק|בדקה|בדקו|טיפל|טיפלה|טיפלו|רשם|רשמה|רשמו|מסר|מסרה|מסרו|אמר|אמרה|אמרו|אתמול|היום|מחר|ביום|במשרד|בבית|בפני|בעניין|בע"מ|לפני|נגד|בדבר|מטעם)[\s\xA0.,;:!?]|$)\p{sc=Hebrew}+(?:['’]\p{sc=Hebrew}+)?(?:-\p{sc=Hebrew}+)?){1,2})(?=[ \t\xA0.,;:!?]|$|[^\p{L}\p{N}])/gu },
|
|
81
110
|
// 5c. Hebrew Inverted Tabu / Registry Format (כהן, אברהם)
|
|
82
|
-
{ name: 'Hebrew Inverted Tabu Name', type: 'NAME', isContextName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?!(
|
|
83
|
-
//
|
|
84
|
-
{ name: '
|
|
111
|
+
{ name: 'Hebrew Inverted Tabu Name', type: 'NAME', isContextName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?!(?:שם|ח\.פ\.?|ת\.ז\.?|כתובת|גוש|חלקה|דירה|קומה|רחוב|עיר|מספר|שלום|היי|אהלן|בוקר|ערב|לילה|תודה|בבקשה|סליחה|אני|אנחנו|אתה|את|הוא|היא|הם|הן|זה|זאת|כן|לא|אבל|או|אם|כי|לכן|אולם|כלומר|למשל|שמי)[,\s])((\p{sc=Hebrew}+(?:['’]\p{sc=Hebrew}+)?(?:-\p{sc=Hebrew}+)?),[ \t\xA0]+(?!(?:אני|אנחנו|אתה|את|הוא|היא|הם|הן|זה|זאת|שלום|תודה|כאן|שם|שמי|הגיש|הגישה|הגישו|אישר|אישרה|אישרו|חתם|חתמה|חתמו|הודיע|הודיעה|הודיעו|טוען|טוענת|טוענים|מייצג|מייצגת|מייצגים|פנה|פנתה|פנו|קבע|קבעה|קבעו|כתב|כתבה|כתבו|נכח|נכחה|נכחו|הורה|הורתה|הורו|סבור|סבורה|סבורים|מבקש|מבקשת|מבקשים|דורש|דורשת|דורשים|העיד|העידה|העידו|הסביר|הסבירה|הסבירו|נפטר|נפטרה|נפטרו|נולד|נולדה|נולדו|הופיע|הופיעה|הופיעו|בדק|בדקה|בדקו|טיפל|טיפלה|טיפלו|רשם|רשמה|רשמו|מסר|מסרה|מסרו|אמר|אמרה|אמרו|אתמול|היום|מחר|ביום|במשרד|בבית|בפני|בעניין|בע"מ|לפני|נגד|בדבר|מטעם)[\s\xA0.,;:!?]|$)\p{sc=Hebrew}+(?:['’]\p{sc=Hebrew}+)?(?:-\p{sc=Hebrew}+)?)(?=[ \t\xA0.,;:!?]|$|[^\p{L}\p{N}])/gu },
|
|
112
|
+
// 5d. Hebrew Conversational Intro Name (אני דוד כהן, שמי דוד כהן, קוראים לי דוד כהן)
|
|
113
|
+
{ name: 'Hebrew Conversational Intro Name', type: 'NAME', isContextName: true, regex: /(?:^|[^\p{L}\p{N}_])(?:שמי|השם\s+שלי(?:\s+הוא)?|קוראים\s+לי|אני)[ \t\xA0]*[:#=-]?[ \t\xA0]+((?!(?:גר|גרה|גרים|עובד|עובדת|עובדים|רוצה|רוצים|צריך|צריכה|מבקש|מבקשת|כותב|כותבת|מדבר|מדברת|פונה|שואל|שואלת|חושב|חושבת|יודע|יודעת|יכול|יכולה|נמצא|נמצאת|מגיע|מגיעה|מתל|מירושלים|מחיפה|מבאר|מרמת|מפתח|מראשון|מנתניה|מאשדוד|מחולון|מבני|מכפר|מהרצליה|מרעננה|ממודיעין)[\s\xA0.,;:!?]|$)\p{sc=Hebrew}{2,}(?:['’]\p{sc=Hebrew}+)?(?:-\p{sc=Hebrew}+)?[ \t\xA0]+(?!(?:מתל|מירושלים|מחיפה|מבאר|מרמת|מפתח|מראשון|מנתניה|מאשדוד|מחולון|מבני|מכפר|מהרצליה|מרעננה|ממודיעין|בעיר|ברחוב|במשרד|בבית|בחברת|ומספר|ותעודת|טלפון|נייד|מייל|אימייל)[\s\xA0.,;:!?]|$)\p{sc=Hebrew}{2,}(?:['’]\p{sc=Hebrew}+)?(?:-\p{sc=Hebrew}+)?)(?=[ \t\xA0.,;:!?]|$|[^\p{L}\p{N}])/gu },
|
|
114
|
+
// 6. Pan-European / Global IBAN (with ISO 7064 Mod 97 validator, case-insensitive)
|
|
115
|
+
{ name: 'International Bank Account Number (IBAN)', type: 'FINANCIAL', validatorType: 'mod97_iban', regex: /\b[A-Z]{2}\d{2}(?:[ \t]?[A-Z0-9]{4}){2,7}(?:[ \t]?[A-Z0-9]{1,4})?\b/gi },
|
|
85
116
|
// 6b. SWIFT / BIC Code
|
|
86
117
|
{ name: 'SWIFT / BIC Code', type: 'FINANCIAL', regex: /\b(?:SWIFT|BIC|SWIFT\/BIC|SWIFT-BIC)[:\s#=-]*([A-Z]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A-Z0-9]{3})?)\b/gi },
|
|
87
118
|
// 7. European VAT / Tax ID (EU / UK / Pan-European VAT with optional spacing)
|
|
@@ -91,7 +122,7 @@ let REGEX_RULES = [
|
|
|
91
122
|
// 7a2. Netherlands KvK Number (Chamber of Commerce / Handelsregister 8 digits)
|
|
92
123
|
{ name: 'Netherlands KvK Number', type: 'ID', regex: /\b(?:KvK(?:[- ]?nummer)?|Kamer\s+van\s+Koophandel)[:\s#=-]*(\d{8})\b/gi },
|
|
93
124
|
// 7b. Netherlands Burgerservicenummer (BSN with 11-proef validator and test range)
|
|
94
|
-
{ name: 'Netherlands National ID (BSN)', type: 'ID', validatorType: 'mod11_bsn', regex: /(?:(?:\b(?:BSN(?:[- ]?nummers?)?|Burgerservicenummer(?:s)?|SOFI(?:[- ]?nummers?)?)[^\S\r\n]*(?:[:#=-]|\bis\b|\bzijn\b)?[^\S\r\n]*)|(
|
|
125
|
+
{ name: 'Netherlands National ID (BSN)', type: 'ID', validatorType: 'mod11_bsn', regex: /(?:(?:\b(?:BSN(?:[- ]?nummers?)?|Burgerservicenummer(?:s)?|SOFI(?:[- ]?nummers?)?)[^\S\r\n]*(?:[:#=-]|\bis\b|\bzijn\b)?[^\S\r\n]*)|(?<![\d-]))(\d{8,9})\b(?![\d-])/gi },
|
|
95
126
|
// 7c. Germany Tax ID (Steuer-ID / IdNr with ISO 7064 Mod 11, 10 validator)
|
|
96
127
|
{ name: 'Germany Tax ID (Steuer-ID / IdNr)', type: 'ID', validatorType: 'mod11_10_de_steuerid', regex: /(?:(?:\b(?:Steuer-?ID|IdNr|Steuernummer)[^\S\r\n]*(?:[:#=-]|\bist\b)?[^\S\r\n]*)|(?<!\d))([1-9]\d{10})\b(?!\d)/gi },
|
|
97
128
|
// 7d. Germany Local Tax Number (Steuernummer)
|
|
@@ -112,6 +143,8 @@ let REGEX_RULES = [
|
|
|
112
143
|
{ name: 'UK Postcode', type: 'ADDRESS', regex: /\b[A-Z]{1,2}\d[A-Z\d]?[ \t\xA0]*\d[A-Z]{2}\b/gi },
|
|
113
144
|
// 9b. Netherlands Postal Code
|
|
114
145
|
{ name: 'Netherlands Postal Code', type: 'ADDRESS', regex: /\b[1-9]\d{3}[ \t\xA0]*(?!SA|SD|SS)[A-Z]{2}\b/g },
|
|
146
|
+
// 9c. Brazil Postal Code (CEP)
|
|
147
|
+
{ name: 'Brazil Postal Code (CEP)', type: 'ADDRESS', regex: /\b(?:CEP[^\S\r\n]*[:#=-]?[^\S\r\n]*\d{5}-?\d{3}|\d{5}-\d{3})\b/gi },
|
|
115
148
|
// 10. UK Bank Sort Code
|
|
116
149
|
{ name: 'UK Bank Sort Code', type: 'FINANCIAL', regex: /(?:(?:\b(?:Sort\s+Code|SC)[:\s#=-]*)|(?<![\d/-]))(\d{2}[- ]\d{2}[- ]\d{2})\b(?!\d|:\d{2})/gi },
|
|
117
150
|
// 10b. UK Bank Account Number (8 digits with explicit Account label)
|
|
@@ -121,27 +154,61 @@ let REGEX_RULES = [
|
|
|
121
154
|
// 12. Canada Postal Code
|
|
122
155
|
{ name: 'Canada Postal Code', type: 'ADDRESS', regex: /\b[A-CEGHJ-NPR-TV-Z]\d[A-CEGHJ-NPR-TV-Z][ \t\xA0]*\d[A-CEGHJ-NPR-TV-Z]\d\b/gi },
|
|
123
156
|
// 13. Australia Tax File Number (TFN with Mod 11 validator)
|
|
124
|
-
{ name: 'Australia Tax File Number (TFN)', type: 'ID', validatorType: 'mod11_tfn', regex: /(?:(?:\bTFN(?:\s*(?:No\.?|Number|#))?[:\s#=-]*)|\b(
|
|
157
|
+
{ name: 'Australia Tax File Number (TFN)', type: 'ID', validatorType: 'mod11_tfn', regex: /(?:(?:\bTFN(?:\s*(?:No\.?|Number|#))?[:\s#=-]*)|\b(?<![\d-]))(\d{3}[- ]?\d{3}[- ]?\d{2,3})\b(?![\d-])/gi },
|
|
125
158
|
// 14. Australia Phone Number
|
|
126
159
|
{ name: 'Australia Phone Number', type: 'PHONE', regex: /(?<!\w)(?:(?:\+?61[-.\s]?|0)(?:4\d{2}[-.\s]?\d{3}[-.\s]?\d{3}|[2378][-.\s]?\d{4}[-.\s]?\d{4}))\b/g },
|
|
127
160
|
// 15. Australia Medicare Card
|
|
128
161
|
{ name: 'Australia Medicare Card', type: 'ID', regex: /(?:\bMedicare(?:\s*(?:No\.?|Number|#))?[:\s#=-]*)\b([2-6]\d{9}(?:[ -]?\d)?)\b/gi },
|
|
129
162
|
// 16. US Passport Number
|
|
130
163
|
{ name: 'US Passport Number', type: 'ID', regex: /(?:\b(?:Passport(?:\s*(?:No\.?|Number|#))?|U\.?S\.?\s+Passport)[:\s#=-]*)\b([A-Z0-9]{9})\b/gi },
|
|
131
|
-
|
|
132
|
-
|
|
164
|
+
// 17. India DPDP National Identifiers (PAN, GSTIN, Aadhaar)
|
|
165
|
+
{ name: 'India Permanent Account Number (PAN)', type: 'ID', regex: /(?:(?:\bPAN(?:\s*(?:Card|No\.?|Number|#))?[:\s#=-]*)|(?<![A-Za-z0-9_-]))([A-Z]{3}[ABCFGHLJPT][A-Z]\d{4}[A-Z])\b(?![A-Za-z0-9_-])/gi },
|
|
166
|
+
{ name: 'India GSTIN', type: 'ID', regex: /\b(?:0[1-9]|[12]\d|3[0-8])[A-Z]{3}[ABCFGHLJPT][A-Z]\d{4}[A-Z][1-9A-Z]Z[0-9A-Z]\b/g },
|
|
167
|
+
{ name: 'India Aadhaar Number', type: 'ID', validatorType: 'aadhaar_in', regex: /(?:\b(?:Aadhaar|UIDAI)(?:\s*(?:No\.?|Number|#))?[:\s#=-]*)([2-9]\d{3}[ -]?\d{4}[ -]?\d{4})\b/gi },
|
|
168
|
+
// 18. Poland National IDs (PESEL with Mod 10 & NIP with Mod 11)
|
|
169
|
+
{ name: 'Poland National ID (PESEL)', type: 'ID', validatorType: 'mod10_pl_pesel', regex: /\bPESEL(?:\s*(?:nr\.?|no\.?|number|#))?[:\s#=-]*(\d{11})\b/gi },
|
|
170
|
+
{ name: 'Poland Tax ID (NIP)', type: 'ID', validatorType: 'mod11_pl_nip', regex: /\bNIP(?:\s*(?:nr\.?|no\.?|number|#))?[:\s#=-]*(\d{3}-\d{3}-\d{2}-\d{2}|\d{3}-\d{2}-\d{2}-\d{3}|\d{10})\b/gi },
|
|
171
|
+
// 19. LATAM National IDs (Mexico CURP & RFC, Argentina CUIT/CUIL, Chile RUT)
|
|
172
|
+
{ name: 'Mexico CURP', type: 'ID', regex: /(?:(?:\bCURP[:\s#=-]*)|(?<![A-Za-z0-9_-]))([A-Z]{4}\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])[HM][A-Z]{5}[0-9A-Z]\d)\b(?![A-Za-z0-9_-])/gi },
|
|
173
|
+
{ name: 'Mexico RFC', type: 'ID', regex: /\bRFC(?:\s*(?:n[º°o]\.?|#))?[:\s#=-]*([A-Z&Ñ]{3,4}\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])[A-Z0-9]{3})\b/gi },
|
|
174
|
+
{ name: 'Argentina CUIT / CUIL', type: 'ID', validatorType: 'mod11_ar_cuit', regex: /(?:(?:\bCUI[TL](?:\s*(?:n[º°o]\.?|#))?[:\s#=-]*)|(?<![\d-]))((?:20|23|24|27|30|33|34)-\d{8}-\d)\b(?![\d-])/gi },
|
|
175
|
+
{ name: 'Chile RUT / RUN', type: 'ID', regex: /\bRU[TN](?:\s*(?:n[º°o]\.?|#))?[:\s#=-]*(\d{1,2}\.\d{3}\.\d{3}-[\dkK]|\d{7,8}-[\dkK])\b/gi },
|
|
176
|
+
// 20. APAC National IDs (Singapore NRIC/FIN, Japan My Number, South Korea RRN, China 18-digit Resident ID, Taiwan National ID, Hong Kong HKID)
|
|
177
|
+
{ name: 'Singapore NRIC / FIN', type: 'ID', regex: /(?:(?:\b(?:NRIC|FIN)(?:\s*(?:No\.?|Number|#))?[:\s#=-]*)|(?<![A-Za-z0-9_-]))([STFGM]\d{7}[A-Z])\b(?![A-Za-z0-9_-])/gi },
|
|
178
|
+
{ name: 'Japan My Number', type: 'ID', regex: /\bMy\s*Number(?:\s*(?:Card|No\.?|Number|#))?[:\s#=-]*(\d{4}[ -]?\d{4}[ -]?\d{4})\b/gi },
|
|
179
|
+
{ name: 'South Korea Resident Registration Number (RRN)', type: 'ID', validatorType: 'mod11_kr_rrn', regex: /(?:(?:\b(?:RRN|Jumin(?:\s*Bunho)?)(?:\s*(?:No\.?|Number|#))?[:\s#=-]*)|(?<![\d-]))(\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])-[1-8]\d{6})\b(?![\d-])/gi },
|
|
180
|
+
{ name: 'China Resident Identity Card (Shenfenzheng)', type: 'ID', validatorType: 'mod11_2_cn_id', regex: /(?:(?:\b(?:Shenfenzheng|CN\s+ID|Resident\s+ID|身份证(?:号|号码)?)[:\s#=-]*)|(?<![A-Za-z0-9_-]))([1-8]\d{5}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx])\b(?![A-Za-z0-9_-])/giu },
|
|
181
|
+
{ name: 'Taiwan National ID', type: 'ID', validatorType: 'mod10_tw_id', regex: /(?:(?:\b(?:TW\s+ID|Taiwan\s+ID|ROC\s+ID|身分證(?:字號)?)[:\s#=-]*)|(?<![A-Za-z0-9_-]))([A-Z][1289]\d{8})\b(?![A-Za-z0-9_-])/giu },
|
|
182
|
+
{ name: 'Hong Kong Identity Card (HKID)', type: 'ID', regex: /(?:(?:\bHKID(?:\s*(?:No\.?|Number|#))?[:\s#=-]*)|(?<![A-Za-z0-9_-]))([A-Z]{1,2}\d{6}\([0-9A]\))(?![A-Za-z0-9_-])/gi },
|
|
183
|
+
// 21. Nordic, Swiss, Belgian, Austrian, Portuguese & UAE National IDs
|
|
184
|
+
{ name: 'Sweden Personnummer', type: 'ID', validatorType: 'luhn_se_personnummer', regex: /(?:(?:\b(?:Personnummer|Samordningsnummer|Pnr)[:\s#=-]*)|(?<![\d-]))((?:19|20)?\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01]|[6-9]\d)[-+]\d{4})\b(?![\d-])/gi },
|
|
185
|
+
{ name: 'Nordic National ID (CPR / Fødselsnummer / HETU)', type: 'ID', regex: /\b(?:CPR(?:-?nummer)?|Fødselsnummer|Foedselsnummer|Henkilötunnus|HETU)[:\s#=-]*(\d{6}[-+A]?\d{3}[\dA-Z]|\d{11})\b/gi },
|
|
186
|
+
{ name: 'Switzerland AHV / AVS Number', type: 'ID', validatorType: 'ean13_ch_ahv', regex: /(?:(?:\b(?:AHV|AVS|OASI)(?:\s*(?:Nr\.?|No\.?|Number|#))?[:\s#=-]*)|(?<![\d.]))(756[.\s-]\d{4}[.\s-]\d{4}[.\s-]\d{2})\b(?![\d.])/gi },
|
|
187
|
+
{ name: 'Belgium National Register Number (NISS)', type: 'ID', regex: /(?:(?:\b(?:Rijksregisternummer|NISS|INSZ|RN)[:\s#=-]*)|(?<![\d.-]))(\d{2}\.\d{2}\.\d{2}-\d{3}\.\d{2})\b(?![\d.-])/gi },
|
|
188
|
+
{ name: 'Austria Sozialversicherungsnummer (SVN)', type: 'ID', regex: /\b(?:SVNR?|Sozialversicherungsnummer|VSNR)[:\s#=-]*(\d{4}[ \t-]?\d{2}(?:0[1-9]|1[0-2])\d{2})\b/gi },
|
|
189
|
+
{ name: 'Portugal NIF (Contribuinte)', type: 'ID', validatorType: 'mod11_pt_nif', regex: /\b(?:PT\s+NIF|NIF|NIPC|Contribuinte)(?:\s*(?:n[º°o]\.?|#))?[:\s#=-]*([1235689]\d{8})\b/gi },
|
|
190
|
+
{ name: 'UAE Emirates ID', type: 'ID', regex: /(?:(?:\bEmirates\s+ID[:\s#=-]*)|(?<![\d-]))(784-\d{4}-\d{7}-\d)\b(?![\d-])/gi },
|
|
191
|
+
|
|
192
|
+
// Emails (Standard, URL-Encoded %40, JSON Unicode-Escaped \u0040, HTML Entities @/@, and Defanged IOCs)
|
|
133
193
|
{ type: 'EMAIL', regex: /\b[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]{1,255}\.[a-zA-Z]{2,}\b/g },
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
194
|
+
{ type: 'EMAIL', regex: /\b[a-zA-Z0-9._+-]{1,64}(?:%40|\\u0040|�*64;|�*40;|@)[a-zA-Z0-9.-]{1,255}\.[a-zA-Z]{2,}\b/gi },
|
|
195
|
+
{ type: 'EMAIL', regex: /\b[a-zA-Z0-9._%+-]{1,64}\s*(?:\[at\]|\(at\)|@)\s*[a-zA-Z0-9.-]{1,255}(?:\s*(?:\[\.\]|\(\.\)|\[dot\]|\(dot\)|\.)\s*[a-zA-Z]{2,})+\b/gi },
|
|
196
|
+
|
|
197
|
+
// Financial Data (Cards, CVV/Exp, Crypto, Direct Deposit & Bank Routing)
|
|
198
|
+
{ type: 'FINANCIAL', regex: /(?<![A-Za-z0-9/_-])\b\d(?:[ -]?\d){12,18}\b(?![A-Za-z0-9/_-])/g },
|
|
199
|
+
{ type: 'FINANCIAL', regex: /\b(?:4\d{3}|5[1-5]\d{2}|222[1-9]|22[3-9]\d|2[3-6]\d{2}|27[01]\d|2720|6(?:011|5\d{2}))(?:\.\d{4}){3}\b/g },
|
|
200
|
+
{ type: 'FINANCIAL', regex: /\b(?:CVV2?|CVC2?|CID|CSC|Security\s+Code|Card\s+Verification)\s*[:#=-]*\s*\d{3,4}\b/gi },
|
|
201
|
+
{ type: 'FINANCIAL', regex: /\b(?:Exp(?:iry|iration|\.)?(?:\s+Date)?|Valid\s+Thru)\s*[:#=-]*\s*(?:0[1-9]|1[0-2])\s*[\/-]\s*(?:\d{2}|\d{4})\b/gi },
|
|
137
202
|
{ type: 'FINANCIAL', regex: /\b(?:1|3|bc1)[a-zA-HJ-NP-Z0-9]{25,39}\b/g },
|
|
138
203
|
{ type: 'FINANCIAL', regex: /\b0x[a-fA-F0-9]{40}\b/g },
|
|
204
|
+
{ type: 'FINANCIAL', regex: /\bT(?=[1-9A-HJ-NP-Za-km-z]*\d)(?=[1-9A-HJ-NP-Za-km-z]*[A-Z])(?=[1-9A-HJ-NP-Za-km-z]*[a-z])[1-9A-HJ-NP-Za-km-z]{33}\b/g },
|
|
205
|
+
{ type: 'FINANCIAL', regex: /\b(?:Solana|SOL)(?:\s+(?:Address|Wallet))?\s*[:=#-]+\s*([1-9A-HJ-NP-Za-km-z]{32,44})\b/gi },
|
|
139
206
|
// Masked / Direct Deposit Bank Account Numbers & Routing Numbers
|
|
140
207
|
{ type: 'FINANCIAL', regex: /\b(?:Account|Acct|Checking|Savings|Direct\s+Deposit)\s*(?:#|ID|No\.?|Number)?[:\s#]*(?:[\*xX•.-]{3,}\d{2,6}|\d{4}[-\s]?\d{4}[-\s]?\d{2,6})\b/gi },
|
|
141
208
|
{ type: 'FINANCIAL', regex: /\b(?:ABA|Routing|RTN)\s*(?:#|ID|No\.?|Number)?[:\s#]*\d{9}\b/gi },
|
|
142
209
|
|
|
143
210
|
// Professional IDs & Organizations
|
|
144
|
-
{ type: 'NAME', isContextName: true, isCorporateName: true, regex: /\b(?:[A-Z\xC0-\u024F][A-Za-z\xC0-\u024F0-9&.'-]*(?<!,)[ \t\xA0]+){1,5}(?:Inc\.?|LLC|Corp\.?|Corporation|Ltd\.?|Limited|Co\.?|Company|Group|Holdings|Solutions|Services|Servicing|Technologies|Logistics|Industries|Capital|Bank|Partners|LLP|PLLC|GmbH(?:\s+&\s+Co\.?\s*KG)?|AG|OHG|KG|UG(?:\s*\(haftungsbeschr[äa]nkt\))?|e\.V\.|Sp\.\s*z\s*o\.o\.|Automotive|Maschinenbau|Anlagenbau|Werkzeugbau|Feintechnik|Elektrotechnik)(?:\s+(?:LLC|Inc\.?|Corp\.?|Ltd\.?|USA|Group))?(?=\b|[.,;:\s]|$)/gu },
|
|
211
|
+
{ type: 'NAME', isContextName: true, isCorporateName: true, regex: /\b(?:[A-Z\xC0-\u024F][A-Za-z\xC0-\u024F0-9&.'-]*(?<!,)[ \t\xA0]+){1,5}(?:Inc\.?|LLC|Corp\.?|Corporation|Ltd\.?|Ltda\.?|Limited|Co\.?|Company|Group|Holdings|Solutions|Services|Servicing|Technologies|Logistics|Industries|Capital|Bank|Partners|LLP|PLLC|S\/A|S\.A\.|EIRELI|GmbH(?:\s+&\s+Co\.?\s*KG)?|AG|OHG|KG|UG(?:\s*\(haftungsbeschr[äa]nkt\))?|e\.V\.|Sp\.\s*z\s*o\.o\.|Automotive|Maschinenbau|Anlagenbau|Werkzeugbau|Feintechnik|Elektrotechnik)(?:\s+(?:LLC|Inc\.?|Corp\.?|Ltd\.?|Ltda\.?|USA|Group))?(?=\b|[.,;:\s]|$)/gu },
|
|
145
212
|
{ type: 'ID', regex: /\b(?:Employee|Emp|EE|Worker|Staff|File|Badge|Member|Advisor|Producer|Agent|Borrower)\s*(?:#|ID|No\.?|Number)[:\s#]*([A-Z0-9-]{3,15})\b/gi },
|
|
146
213
|
{ type: 'ID', regex: /\b(?:Pay\s+Group[:#\s]+[A-Za-z0-9_-]{2,30}|(?:Cost\s+Center|Dept|Department)[:#\s]+[A-Za-z0-9_-]*\d[A-Za-z0-9_-]*)\b/gi },
|
|
147
214
|
{ type: 'ID', regex: /(?:\b(?:Box\s+d\b|d\.\s*(?:Control|#|number|no\.?|num)|d\s+Control)\s*(?:Control\s+)?(?:number|no\.?|#|num)?[:\s#]+|\bControl\s*(?:number|no\.?|#|num)?[:\s#]+|\bControl[:#]\s*)([A-Za-z0-9-]{3,30})/gi },
|
|
@@ -155,15 +222,15 @@ let REGEX_RULES = [
|
|
|
155
222
|
{ type: 'ADDRESS', regex: /\b(?:P\.?O\.?[ \t\xA0]*Box|PO[ \t\xA0]*Box|Postbus|Postfach|(?:BP|B\.P\.)(?![ \t\xA0]*\d{2,3}\s*\/\s*\d{2,3}(?:[ \t\xA0]*(?:mmHg|mm\s*Hg))?)|Bo[îi]te[ \t\xA0]+Postale|Apartado(?:[ \t\xA0]+de[ \t\xA0]+Correos)?|Apdo\.|Casella[ \t\xA0]+Postale)[ \t\xA0]+(?:[A-Z0-9-]{1,8}(?:[ \t\xA0]+[A-Z0-9-]{1,8}){0,3}|\d{1,6})\b(?:[ \t\xA0]*,?[ \t\xA0]*(?:(?:[1-9]\d{3}[ \t\xA0]*(?!SA|SD|SS)[A-Z]{2}|\d{4,5})[ \t\xA0]+[\p{Lu}][\p{L}'’-]+))?/giu },
|
|
156
223
|
// European Street Addresses (Dutch / Netherlands: Canals, Dijk, Kade, Straat, Laan, Plein)
|
|
157
224
|
{ type: 'ADDRESS', regex: /\b(?:(?:[A-Z\p{Lu}][\p{L}'’-]*(?:gracht|kade|singel|dijk|weg|straat|laan|plein|steeg|dreef|burgwal|dam|rak)|Damrak|Coolsingel|Rokin|Spui|(?:[A-Z\p{Lu}][\p{L}'’-]+[ \t\xA0]+)+(?:gracht|kade|singel|dijk|weg|straat|laan|plein|steeg|dreef|burgwal|dam|rak))\b[ \t\xA0]+\d{1,4}[a-zA-Z]?(?:[ \t\xA0]*,?[ \t\xA0]*(?:(?:[1-9]\d{3}[ \t\xA0]*(?!SA|SD|SS)[A-Z]{2})?[ \t\xA0]+[\p{Lu}][\p{L}'’-]+))?)/giu },
|
|
158
|
-
// European Street Addresses (
|
|
159
|
-
{ type: 'ADDRESS', regex: /(?:(?:\b[1-9]\d{0,3}[a-zA-Z]?[, \t\xA0]+\b(?:Rue|(?:(?<!\b(?:Fed|Federal|State|Local|U\.?S\.?)\.?\s+)R\.(?!\s+(?:Civ|Crim|App|Evid|Bankr|Pro|Proc|Jud)\b))|Avenue|Av\.|Avda\.|Boulevard|Blvd|Bd|Allée|Allee|Chemin|Quai|Impasse|Sq\.|Rte|Calle|C\/|Paseo|P\.º|Rambla|Plaza|Plza\.|Ronda|Travesía|Travesia|(?:(?<!\b(?:sent|executed|shipped|delivered|via|routed|available|transferred|transfer|transfers|convey|conveys|conveyed|grant|granted|grants|accessible|authenticated|verified|signed|recorded|record|evaluated|administered|assessed|measured|determined|reported|tested|analyzed|handled|managed|operated|provided|arranged|booked|conducted|performed|payout|pay|paid|authorized|process|processed|received|issued|remitted|dispatch|dispatched)\s+)Via(?!\s+(?:DOCUSIGN|TRANSCRIPT|EMAIL|API|PORTAL|FEED|SERVICE|WEBHOOK|SMS|HTTP|HTTPS|FTP|TCP|IP|VPN|SSH|APP|LINK|AUTH|METHOD|ID|NUMBER|NO|REF|CODE|Federal(?:\s+Reserve)?|Fedwire|SWIFT|ACH|RTGS|CHIPS|SEPA|BACS|Target2|Bank|Wire|Grant(?:\s+Deed)?|Warranty(?:\s+Deed)?|Quitclaim(?:\s+Deed)?|Deed|CTCAE|MedDRA|WHO|FDA|EMA|ICH|GCP|IV|SC|Oral|IBAN|ACCOUNT|ROUTING|WIRE|TRANSFER|CARD|PAYMENT|PAYOUT|DEBIT|CREDIT|CRYPTO|PAYPAL|TOKEN|KEY|DEPLOY|SSH|SECRET|CHECK|CHEQUE|INVOICE|ORDER|SETTLEMENT)\b))|Viale|V\.le|Corso|C\.so|Piazza|P\.zza|Largo|Vicolo|Avenida|Praceta|Praça|Praca|Alameda|Travessa|Calçada|Calcada|(?:Place|Square|Route|Passage|Cours|Voie)(?=[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}]))[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*(?:[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*){0,4}(?:[, \t\xA0]+(?:(?:F-|D-|ES-|IT-|FR-|NL-|CH-|AT-|PT-)?\d{4,5}(?:-\d{3,4})?)[ \t\xA0]+[\p{Lu}][\p{L}'-]+)?)|(?:\b(?:Rue|(?:(?<!\b(?:Fed|Federal|State|Local|U\.?S\.?)\.?\s+)R\.(?!\s+(?:Civ|Crim|App|Evid|Bankr|Pro|Proc|Jud)\b))|Avenue|Av\.|Avda\.|Boulevard|Blvd|Bd|Allée|Allee|Chemin|Quai|Impasse|Sq\.|Rte|Calle|C\/|Paseo|P\.º|Rambla|Plaza|Plza\.|Ronda|Travesía|Travesia|(?:(?<!\b(?:sent|executed|shipped|delivered|via|routed|available|transferred|transfer|transfers|convey|conveys|conveyed|grant|granted|grants|accessible|authenticated|verified|signed|recorded|record|evaluated|administered|assessed|measured|determined|reported|tested|analyzed|handled|managed|operated|provided|arranged|booked|conducted|performed|payout|pay|paid|authorized|process|processed|received|issued|remitted|dispatch|dispatched)\s+)Via(?!\s+(?:DOCUSIGN|TRANSCRIPT|EMAIL|API|PORTAL|FEED|SERVICE|WEBHOOK|SMS|HTTP|HTTPS|FTP|TCP|IP|VPN|SSH|APP|LINK|AUTH|METHOD|ID|NUMBER|NO|REF|CODE|Federal(?:\s+Reserve)?|Fedwire|SWIFT|ACH|RTGS|CHIPS|SEPA|BACS|Target2|Bank|Wire|Grant(?:\s+Deed)?|Warranty(?:\s+Deed)?|Quitclaim(?:\s+Deed)?|Deed|CTCAE|MedDRA|WHO|FDA|EMA|ICH|GCP|IV|SC|Oral|IBAN|ACCOUNT|ROUTING|WIRE|TRANSFER|CARD|PAYMENT|PAYOUT|DEBIT|CREDIT|CRYPTO|PAYPAL|TOKEN|KEY|DEPLOY|SSH|SECRET|CHECK|CHEQUE|INVOICE|ORDER|SETTLEMENT)\b))|Viale|V\.le|Corso|C\.so|Piazza|P\.zza|Largo|Vicolo|Avenida|Praceta|Praça|Praca|Alameda|Travessa|Calçada|Calcada|(?:Place|Square|Route|Passage|Cours|Voie)(?=[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}]))[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*(?:[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*){0,4}(?:(?:[, \t\xA0]+(?:nº|n°|no\.?|num\.?|#)?[ \t\xA0]*\b[1-9]\d{0,
|
|
225
|
+
// European & Brazilian/Romance Street Addresses (France, Spain, Italy, Portugal, Brazil: Rua, Avenida, Av., Alameda, Praça, Rodovia, etc.)
|
|
226
|
+
{ type: 'ADDRESS', regex: /(?:(?:\b[1-9]\d{0,3}[a-zA-Z]?[, \t\xA0]+\b(?:Rue|Rua|Rodovia|Estrada|(?:(?<!\b(?:Fed|Federal|State|Local|U\.?S\.?)\.?\s+)R\.(?!\s+(?:Civ|Crim|App|Evid|Bankr|Pro|Proc|Jud)\b))|Avenue|Av\.|Avda\.|Boulevard|Blvd|Bd|Allée|Allee|Chemin|Quai|Impasse|Sq\.|Rte|Calle|C\/|Paseo|P\.º|Rambla|Plaza|Plza\.|Ronda|Travesía|Travesia|(?:(?<!\b(?:sent|executed|shipped|delivered|via|routed|available|transferred|transfer|transfers|convey|conveys|conveyed|grant|granted|grants|accessible|authenticated|verified|signed|recorded|record|evaluated|administered|assessed|measured|determined|reported|tested|analyzed|handled|managed|operated|provided|arranged|booked|conducted|performed|payout|pay|paid|authorized|process|processed|received|issued|remitted|dispatch|dispatched)\s+)Via(?!\s+(?:DOCUSIGN|TRANSCRIPT|EMAIL|API|PORTAL|FEED|SERVICE|WEBHOOK|SMS|HTTP|HTTPS|FTP|TCP|IP|VPN|SSH|APP|LINK|AUTH|METHOD|ID|NUMBER|NO|REF|CODE|Federal(?:\s+Reserve)?|Fedwire|SWIFT|ACH|RTGS|CHIPS|SEPA|BACS|Target2|Bank|Wire|Grant(?:\s+Deed)?|Warranty(?:\s+Deed)?|Quitclaim(?:\s+Deed)?|Deed|CTCAE|MedDRA|WHO|FDA|EMA|ICH|GCP|IV|SC|Oral|IBAN|ACCOUNT|ROUTING|WIRE|TRANSFER|CARD|PAYMENT|PAYOUT|DEBIT|CREDIT|CRYPTO|PAYPAL|TOKEN|KEY|DEPLOY|SSH|SECRET|CHECK|CHEQUE|INVOICE|ORDER|SETTLEMENT)\b))|Viale|V\.le|Corso|C\.so|Piazza|P\.zza|Largo|Vicolo|Avenida|Praceta|Praça|Praca|Alameda|Travessa|Calçada|Calcada|(?:Place|Square|Route|Passage|Cours|Voie)(?=[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}]))[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*(?:[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*){0,4}(?:[, \t\xA0]+(?:(?:F-|D-|ES-|IT-|FR-|NL-|CH-|AT-|PT-)?\d{4,5}(?:-\d{3,4})?)[ \t\xA0]+[\p{Lu}][\p{L}'-]+)?)|(?:\b(?:Rue|Rua|Rodovia|Estrada|(?:(?<!\b(?:Fed|Federal|State|Local|U\.?S\.?)\.?\s+)R\.(?!\s+(?:Civ|Crim|App|Evid|Bankr|Pro|Proc|Jud)\b))|Avenue|Av\.|Avda\.|Boulevard|Blvd|Bd|Allée|Allee|Chemin|Quai|Impasse|Sq\.|Rte|Calle|C\/|Paseo|P\.º|Rambla|Plaza|Plza\.|Ronda|Travesía|Travesia|(?:(?<!\b(?:sent|executed|shipped|delivered|via|routed|available|transferred|transfer|transfers|convey|conveys|conveyed|grant|granted|grants|accessible|authenticated|verified|signed|recorded|record|evaluated|administered|assessed|measured|determined|reported|tested|analyzed|handled|managed|operated|provided|arranged|booked|conducted|performed|payout|pay|paid|authorized|process|processed|received|issued|remitted|dispatch|dispatched)\s+)Via(?!\s+(?:DOCUSIGN|TRANSCRIPT|EMAIL|API|PORTAL|FEED|SERVICE|WEBHOOK|SMS|HTTP|HTTPS|FTP|TCP|IP|VPN|SSH|APP|LINK|AUTH|METHOD|ID|NUMBER|NO|REF|CODE|Federal(?:\s+Reserve)?|Fedwire|SWIFT|ACH|RTGS|CHIPS|SEPA|BACS|Target2|Bank|Wire|Grant(?:\s+Deed)?|Warranty(?:\s+Deed)?|Quitclaim(?:\s+Deed)?|Deed|CTCAE|MedDRA|WHO|FDA|EMA|ICH|GCP|IV|SC|Oral|IBAN|ACCOUNT|ROUTING|WIRE|TRANSFER|CARD|PAYMENT|PAYOUT|DEBIT|CREDIT|CRYPTO|PAYPAL|TOKEN|KEY|DEPLOY|SSH|SECRET|CHECK|CHEQUE|INVOICE|ORDER|SETTLEMENT)\b))|Viale|V\.le|Corso|C\.so|Piazza|P\.zza|Largo|Vicolo|Avenida|Praceta|Praça|Praca|Alameda|Travessa|Calçada|Calcada|(?:Place|Square|Route|Passage|Cours|Voie)(?=[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}]))[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*(?:[ \t\xA0]+(?:(?:de[ \t\xA0]+la|de[ \t\xA0]+l'|de[ \t\xA0]+l’|de[ \t\xA0]+los|de[ \t\xA0]+las|de[ \t\xA0]+|des[ \t\xA0]+|du[ \t\xA0]+|del[ \t\xA0]+|dels[ \t\xA0]+|delle[ \t\xA0]+|degli[ \t\xA0]+|dei[ \t\xA0]+|d'|d’|da[ \t\xA0]+|do[ \t\xA0]+|dos[ \t\xA0]+|das[ \t\xA0]+)[ \t\xA0]*)?[\p{Lu}][\p{L}'’.-]*){0,4}(?:(?:[, \t\xA0]+(?:nº|n°|no\.?|num\.?|#)?[ \t\xA0]*\b[1-9]\d{0,4}[a-zA-Z]?\b(?!\d)(?:[ \t\xA0]*,?[ \t\xA0]*(?:Apto\.?|Ap\.?|Apartamento|Bloco|Sala|Conj\.?|Conjunto)[ \t\xA0]*[A-Za-z0-9-]+)?(?:[, \t\xA0]+(?:(?:F-|D-|ES-|IT-|FR-|NL-|CH-|AT-|PT-)?\d{4,5}(?:-\d{3,4})?)[ \t\xA0]+[\p{Lu}][\p{L}'-]+)?)|(?:[, \t\xA0]+(?:(?:F-|D-|ES-|IT-|FR-|NL-|CH-|AT-|PT-)?\d{4,5}(?:-\d{3,4})?)[ \t\xA0]+[\p{Lu}][\p{L}'-]+))))/giu },
|
|
160
227
|
// European Street Addresses (Germanic: Germany, Austria, Switzerland, etc.)
|
|
161
228
|
{ type: 'ADDRESS', regex: /\b(?:(?:Am|An\s+der|An\s+dem|Unter\s+den|Auf\s+dem|Auf\s+der|Beim|Zum|Vor\s+dem)[ \t\xA0]+[\p{Lu}][\p{L}.-]+(?:[ \t\xA0]+[\p{Lu}][\p{L}.-]+)?|(?:[\p{Lu}][\p{L}.-]+[ \t\xA0]+(?:Straße|Strasse|Weg|Gasse|Allee|Damm|Ring|Platz|Ufer|Chaussee|Pfad|Zeile|Markt|Tor|Str\.)|[\p{Lu}][\p{L}.-]*(?:straße|strasse|str\.|weg|gasse|allee|damm|ring|platz|ufer|chaussee|pfad|zeile|graben|markt|tor)))\b[ \t\xA0]+\b\d{1,4}[a-zA-Z]?\b(?!\d)(?:[ \t\xA0]*,?[ \t\xA0]*(?:Wohnung|Whg|App|Zimmer|Stock|Etage|OG|EG)\.?[ \t\xA0]*[A-Za-z0-9-]+)?(?:[, \t\xA0]+(?:D-|AT-|CH-)?\d{4,5}[ \t\xA0]+[\p{Lu}][\p{L}'-]+)?/giu },
|
|
162
229
|
{ type: 'ADDRESS', regex: /\b[A-Za-z][a-zA-Z\s.-]{1,25},?\s+(?:AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY|DC|PR)\s+\d{5}(?:-\d{4})?\b/g },
|
|
163
230
|
{ type: 'ADDRESS', regex: /\b(?:ZIP|Postal|Code)?\s*(?:AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY|DC|PR)\s+\d{5}(?:-\d{4})?\b/g },
|
|
164
231
|
{ type: 'ADDRESS', regex: /\b\d{5}-\d{4}\b/g },
|
|
165
|
-
// SSN / National IDs
|
|
166
|
-
{ type: 'ID', regex: /\b\d{3}
|
|
232
|
+
// SSN / National IDs (including JSON Unicode-escaped \u002d and URL-encoded %2D)
|
|
233
|
+
{ type: 'ID', regex: /\b\d{3}(?:-|%2D|\\u002d)\d{2}(?:-|%2D|\\u002d)\d{4}\b/gi },
|
|
167
234
|
{ type: 'ID', regex: /(?<=^|[^\w*])(?:\*{3}|X{3}|x{3}|\*{2}|X{2}|x{2})[ -]?(?:\*{2}|X{2}|x{2})\b/gi },
|
|
168
235
|
{ type: 'ID', regex: /(?<=^|[^\w*])(?:\*{3}|X{3}|x{3}|\*{2}|X{2}|x{2})[ -]?(?:\*{2}|X{2}|x{2})[ -]?\d{4}\b/g },
|
|
169
236
|
{ type: 'ID', regex: /\b\d{2}-\d{7}\b/g },
|
|
@@ -172,11 +239,25 @@ let REGEX_RULES = [
|
|
|
172
239
|
{ type: 'LOCATION', regex: /\b[A-Za-z][a-zA-Z .'-]{1,25},\s*(?:AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY|DC|PR)\b/g },
|
|
173
240
|
|
|
174
241
|
// General Privacy, Dates & Secrets
|
|
175
|
-
{ type: 'DATE', regex: /\b(?:DOB|BIRTHDAY|Date
|
|
242
|
+
{ type: 'DATE', regex: /\b(?:DOB|BIRTHDAY|Date\s+of\s+Birth|Data\s+de\s+Nascimento|Fecha\s+de\s+Nacimiento|Date\s+de\s+naissance|Geburtsdatum|born(?:\s+on)?)[\s:#=-]+([0-9./-]{6,10}|(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember))\.?\s+\d{1,2}(?:st|nd|rd|th)?,?\s+\d{4}|\d{1,2}(?:st|nd|rd|th)?\s+(?:of\s+)?(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember))\.?,?\s+\d{4})\b/gi },
|
|
176
243
|
{ type: 'SECRET', regex: /\b(?:PASSWORD|PWD|SECRET)\s*[:=]\s*["']?[\S]{4,}["']?/gi },
|
|
244
|
+
{ type: 'SECRET', regex: /(?:\bcurl\b[^\r\n]*?\s(?:-u|--user)\s+["']?[A-Za-z0-9_.+-]+:[^\s"']+|\b(?:--password|--api-key|--apikey|--access-token|--auth-token|--client-secret|--secret-key|--private-key)(?:=|\s+)["']?[^\s"']{6,}["']?)/gi },
|
|
245
|
+
{ type: 'SECRET', regex: /\b(?:X-API-Key|X-Amz-Security-Token|X-Functions-Key|X-Shopify-Access-Token|X-Auth-Token|Api-Key)\s*:\s*["']?[A-Za-z0-9_.\-~+/=]{12,}["']?/gi },
|
|
246
|
+
{ type: 'SECRET', regex: /(?:DefaultEndpointsProtocol=https?;AccountName=[^;\s"']+;AccountKey=[A-Za-z0-9+/=]{20,}(?:;EndpointSuffix=[^;\s"']+)?|Endpoint=sb:\/\/[^;\s"']+;SharedAccessKeyName=[^;\s"']+;SharedAccessKey=[A-Za-z0-9+/=]{16,}|\bSharedAccessSignature=sr=[^\s"']+&sig=[A-Za-z0-9%/+=]{16,}|\bAccountKey=[A-Za-z0-9+/=]{40,88}==)/gi },
|
|
247
|
+
{ type: 'SECRET', regex: /\b(?:h(?:tt|xx)ps?|s?f(?:t|x)p|wss?):\/\/[a-zA-Z0-9_.%+-]+:[^\s/@:"']+@[a-zA-Z0-9_.-]+(?:(?:\[\.\]|\(\.\))[a-zA-Z0-9_.-]+)*(?::\d+)?(?:\/[^\s"']*)?/gi },
|
|
248
|
+
{ type: 'SECRET', regex: /(?<=["']?(?:auth|identitytoken|registrytoken|\.dockerconfigjson)["']?\s*:\s*["'])[A-Za-z0-9+/=]{16,}(?=["'])/gi },
|
|
249
|
+
{ type: 'SECRET', regex: /\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^\s"']+/gi },
|
|
250
|
+
{ type: 'SECRET', regex: /(?<=\bAuthorization\s*:\s*Basic\s+)[A-Za-z0-9+/=]{8,}(?![A-Za-z0-9+/=])/gi },
|
|
251
|
+
{ type: 'SECRET', regex: /(?<![A-Za-z0-9])(?:\$2[aby]\$\d{2}\$[./A-Za-z0-9=]{20,60}|\$argon2(?:id|i|d)\$[^\s"']{15,120})/g },
|
|
252
|
+
{ type: 'SECRET', regex: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
253
|
+
{ type: 'SECRET', regex: /\bsk-ant-(?:api\d{2}|admin\d{2}|sid\d{2})-[a-zA-Z0-9_-]{16,128}\b/g },
|
|
254
|
+
{ type: 'SECRET', regex: /\bhttps:\/\/(?:hooks\.slack\.com\/services\/T[A-Z0-9_]+\/B[A-Z0-9_]+\/[A-Za-z0-9_-]+|(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks\/\d{17,20}\/[A-Za-z0-9_-]{60,70})\b/gi },
|
|
255
|
+
{ type: 'SECRET', regex: /\b\d{8,10}:AA[A-Za-z0-9_-]{33}\b/g },
|
|
256
|
+
{ type: 'SECRET', regex: /\bAGE-SECRET-KEY-1[A-Z0-9]{58}\b/g },
|
|
257
|
+
{ type: 'SECRET', regex: /\b(?:sbp_[a-fA-F0-9]{40}|dop_v1_[a-fA-F0-9]{64}|doo_v1_[a-fA-F0-9]{64}|dp\.(?:st|pt|ct|sa)\.[a-zA-Z0-9_-]{20,}|lin_api_[a-zA-Z0-9]{32,64}|ntn_[a-zA-Z0-9]{32,64}|secret_[a-zA-Z0-9]{32,64}|gsk_[a-zA-Z0-9]{32,64}|r8_[a-zA-Z0-9]{24,64}|tvly-[a-zA-Z0-9_-]{20,64}|fc-[a-fA-F0-9]{32}|dapi[a-fA-F0-9]{32}(?:-\d)?|re_[a-zA-Z0-9_]{20,64}|pypi-[A-Za-z0-9_-]{16,128}|whsec_[A-Za-z0-9+/=_-]{24,128}|shpat_[a-fA-F0-9]{32}|shpss_[a-fA-F0-9]{32}|shpca_[a-fA-F0-9]{32}|shppa_[a-fA-F0-9]{32}|hvs\.[A-Za-z0-9_-]{24,128}|hvb\.[A-Za-z0-9_-]{24,128}|glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8}|glc_[A-Za-z0-9+/=_-]{20,128}|pscale_tkn_[A-Za-z0-9_.-]{20,64}|pscale_pw_[A-Za-z0-9_.-]{20,64}|pat[A-Za-z0-9]{14}\.[a-fA-F0-9]{64}|pat-(?:na1|eu1)-[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}|sq0atp-[A-Za-z0-9_-]{22,64}|sq0csp-[A-Za-z0-9_-]{32,64}|NRAK-[A-Z0-9]{27}|v1\.0-[a-fA-F0-9]{24}-[a-fA-F0-9]{16,160}|ATATT3xFfGF0[A-Za-z0-9+/=_-]{24,128}|tskey-(?:auth|api|client)-[A-Za-z0-9_-]{20,96}|sntry[su]_[A-Za-z0-9+/=_-]{32,160}|(?:pk|sk)\.eyJ1[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{16,}|key-[a-f0-9]{32}|[a-f0-9]{32}-us\d{1,2}|napi_[a-zA-Z0-9]{32,64}|[a-zA-Z0-9]{14}\.atlasv1\.[a-zA-Z0-9]{50,80})\b/g },
|
|
177
258
|
|
|
178
259
|
// Standard IDs (SSN, EIN, Passport, VAT, European National IDs)
|
|
179
|
-
{ type: 'ID', regex: /\b\d{3}
|
|
260
|
+
{ type: 'ID', regex: /\b\d{3}(?:-|%2D|\\u002d)\d{2}(?:-|%2D|\\u002d)\d{4}\b/gi },
|
|
180
261
|
{ type: 'ID', regex: /\b(?:XXX|xxx|\*\*\*)[ -]?(?:XX|xx|\*\*)[ -]?\d{4}\b/g },
|
|
181
262
|
{ type: 'ID', regex: /\b\d{2}-\d{7}\b/g },
|
|
182
263
|
{ type: 'ID', regex: /(?:(?:[A-Za-z]:\\|\/(?:usr|var|etc|home|root|Users|private|tmp|opt|bin|sbin|dev|Applications|Library)\/)[a-zA-Z0-9_.-]+(?:[\/\\][a-zA-Z0-9_.-]+)*|\/(?:[a-zA-Z0-9_.-]+\/)+[a-zA-Z0-9_.-]+\.(?:txt|pdf|docx|xlsx|csv|js|ts|json|env|log|key|pem|crt|conf|yaml|yml|xml|html|sql|py|go|rs|c|cpp|h|sh|bin|zip|tar|gz|png|jpg|jpeg|svg|webp|wasm)\b)/g },
|
|
@@ -185,12 +266,15 @@ let REGEX_RULES = [
|
|
|
185
266
|
// Netherlands Chamber of Commerce (KvK)
|
|
186
267
|
{ type: 'ID', regex: /\b(?:KvK|Kamer\s+van\s+Koophandel)[^\S\r\n]*[:#=-]?[^\S\r\n]*(\d{8})\b/gi },
|
|
187
268
|
{ type: 'ID', regex: /\b[A-Z]{2}[0-9]{6,12}\b/gi },
|
|
188
|
-
{ type: 'ID', regex: /[A-Z0-9<]{30,44}/g },
|
|
269
|
+
{ type: 'ID', regex: /(?<![a-zA-Z0-9/_-])[A-Z0-9<]{30,44}(?![a-zA-Z0-9/_-])/g },
|
|
189
270
|
|
|
190
|
-
// IT / Technical IDs
|
|
271
|
+
// IT / Technical IDs (IPv4-mapped IPv6, IPv4, Defanged IPv4, Full & Compressed IPv6, MAC Address, UUID)
|
|
272
|
+
{ type: 'IP', regex: /(?:(?:\b(?:0{1,4}:){5}ffff:)|::(?:ffff:)?)(?:\d{1,3}\.){3}\d{1,3}\b/gi },
|
|
191
273
|
{ type: 'IP', regex: /(?<!\b(?:Chrome|Version|Firefox|Safari|Edge|Edg|OPR|Opera|Brave|V8|Node|Electron)\/)\b(?!(?:0\.0\.0\.0|127\.0\.0\.1)\b)(?:\d{1,3}\.){3}\d{1,3}\/(?:[0-9]|[12]\d|3[0-2])\b/g },
|
|
192
274
|
{ type: 'IP', regex: /(?<!\b(?:Chrome|Version|Firefox|Safari|Edge|Edg|OPR|Opera|Brave|V8|Node|Electron)\/)\b(?!(?:0\.0\.0\.0|127\.0\.0\.1)\b)(?:\d{1,3}\.){3}\d{1,3}\b/g },
|
|
193
|
-
{ type: 'IP', regex: /\b(
|
|
275
|
+
{ type: 'IP', regex: /\b\d{1,3}(?:\[\.\]|\(\.\)|\.)\d{1,3}(?:\[\.\]|\(\.\)|\.)\d{1,3}(?:\[\.\]|\(\.\))\d{1,3}\b/g },
|
|
276
|
+
{ type: 'IP', regex: /\b(?:(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}|(?:[a-fA-F0-9]{1,4}:){1,7}:(?:[a-fA-F0-9]{1,4}(?::[a-fA-F0-9]{1,4}){0,6})?|::(?:[a-fA-F0-9]{1,4}(?::[a-fA-F0-9]{1,4}){0,6})?)(?:%[0-9a-zA-Z]{1,})?(?![:a-fA-F0-9])/g },
|
|
277
|
+
{ type: 'ID', regex: /\b(?:[0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}\b|\b(?:[0-9A-Fa-f]{2}-){5}[0-9A-Fa-f]{2}\b/g },
|
|
194
278
|
{ type: 'ID', regex: /\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g },
|
|
195
279
|
{ type: 'ID', regex: /(?<!\b(?:GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS|CONNECT|TRACE)\s+)(?<![:/A-Za-z0-9])(?:\/[a-zA-Z0-9_.-]+(?:[\/\\][a-zA-Z0-9_.-]+)+|\b[a-zA-Z]:\\[\w.-]+(?:\\[\w.-]+)*)/g },
|
|
196
280
|
{ type: 'ID', regex: /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}(?::\d{2})?)?\b/g },
|
|
@@ -198,12 +282,12 @@ let REGEX_RULES = [
|
|
|
198
282
|
{ type: 'ID', regex: /(?<!\[)\b\d{2}\/\d{2}\/\d{4}\b(?![ \t\xA0]*(?:,\s*)?\d{1,2}:\d{2})/g },
|
|
199
283
|
|
|
200
284
|
// Phone Numbers
|
|
201
|
-
{ type: 'PHONE', regex: /(?<!\b(?:DFARS|FAR|CFR)\s+)(
|
|
285
|
+
{ type: 'PHONE', regex: /(?<!\b(?:DFARS|FAR|CFR)\s+)(?<![\w.])(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}(?:\s*(?:ext\.?|x)\s*\d{1,5})?\b(?!\.\d)/gi },
|
|
202
286
|
{ type: 'PHONE', regex: /(?<!\w)(?:(?:Durchwahl|DW(?:[ \t]+ist)?|App\.|Kl\.)[:\s#=-]*\d{2,5}|intern[ \t]*[:#/-]+[ \t]*\d{2,5}|(?<=\b(?:Tel(?:efon)?|Phone|Fon|Durchwahl|DW|Rufnummer|unter)[:\s,]+(?:ist\s+)?(?:\d{2,5}[,\s]+)?)intern[ \t]*\d{2,5}|intern[ \t]*\d{2,5}(?=\s*(?:erreichbar|anrufen|wählen|durchrufen|kontaktieren))|\bintern(?:e)?\s+(?:Durchwahl|DW|Apparat|Rufnummer|Nummer|Nr\.?)[:\s#=-]*\d{2,5})\b/gi },
|
|
203
287
|
{ type: 'PHONE', regex: /\+\d{1,3}[ \t.-]+(?:\(?\d{1,4}\)?[ \t.-]+)?\d{2,8}(?:[ \t.-]+\d{2,8}){0,4}\b/g },
|
|
204
288
|
{ type: 'PHONE', regex: /\+?[1-9]\d{1,3}[\s.-]\(?\d{1,4}\)?[\s.-]\d{2,4}[\s.-]\d{4}/g },
|
|
205
289
|
{ type: 'PHONE', regex: /(?:\+44\s?7\d{3}|\(?07\d{3}\)?)\s?\d{3}\s?\d{3}\b/g },
|
|
206
|
-
{ type: 'PHONE', regex: /(?<!\b(?:DFARS|FAR|CFR)\s+)(?<![A-Za-z0-9.-])\b(?:\d{3}[-.\s]\d{4}|\(\d{3}\)\s??\d{3}[-.\s]??\d{4}|\d{3}[-.\s]??\d{3}[-.\s]??\d{4})\b(?![A-Za-z0-9-])/g },
|
|
290
|
+
{ type: 'PHONE', regex: /(?<!\b(?:DFARS|FAR|CFR)\s+)(?<![A-Za-z0-9.-])\b(?:\d{3}[-.\s]\d{4}|\(\d{3}\)\s??\d{3}[-.\s]??\d{4}|\d{3}[-.\s]??\d{3}[-.\s]??\d{4})\b(?![A-Za-z0-9-]|\.\d)/g },
|
|
207
291
|
|
|
208
292
|
// Geolocation (Lat/Long)
|
|
209
293
|
{ type: 'LOCATION', regex: /\b-?\d{1,3}\.\d{4,6}[° ]?[NSns],\s*-?\d{1,3}\.\d{4,6}[° ]?[EWew]\b/g },
|
|
@@ -214,23 +298,23 @@ let REGEX_RULES = [
|
|
|
214
298
|
{ type: 'ID', regex: /\bDRIVER[S]?\s+LICENSE[ -]?\d{6,15}\b/gi },
|
|
215
299
|
|
|
216
300
|
// Names with Honorifics (International & European: Dr., Prof., Mr., Sir, Lord, Herr, Frau, Me, Avv., Dott.ssa, Don, Dhr., etc.)
|
|
217
|
-
{ name: 'Names with Honorifics', type: 'NAME', isContextName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?:Kollege|Kollegin|Instandhalter|Instandhalterin|Disponent|Disponentin|Werkstudent|Werkstudentin|Lagerleiter|Lagerleiterin|Arbeitsvorbereiter|Arbeitsvorbereiterin|Qualitätsprüfer|Qualitätsprüferin|Dott\.ssa|Sig\.ra|Mr|Mrs|Ms|Miss|Dr|Prof|Hon|Rev|Judge|Atty|Doctor|Professor|Sir|Lord|Lady|Dame|Herr|Frau|Rechtsanwalt|Rechtsanwältin|Notar|Schichtleiter|Schichtleiterin|Schichtführer|Schichtführerin|Teamleiter(?:in)?\s+(?:Produktion|Entwicklung|Qualität|Vertrieb|Logistik|Fertigung)|Teamleiter|Teamleiterin|Einrichter|Einrichterin|Laborant|Laborantin|Betriebsratssprecher|Betriebsratssprecherin|Meister|Meisterin|Geschäftsführer|Geschäftsführerin|Projektleiter|Projektleiterin|Abteilungsleiter|Abteilungsleiterin|Bereichsleiter|Bereichsleiterin|Betriebsleiter|Betriebsleiterin|Werkleiter|Werkleiterin|Produktionsleiter|Produktionsleiterin|Qualitätsleiter|Qualitätsleiterin|Assistent|Assistentin|Ansprechpartner|Ansprechpartnerin|Prüfer|Prüferin|Monteur|Monteurin|Inbetriebnehmer|Inbetriebnehmerin|Vorstand|Mme|Mlle|Me|Monsieur|Madame|Mademoiselle|Maître|Don|Doña|Señor|Señora|Avvocato|Dottore|Dottoressa|Ingegnere|Signor|Signora|Dhr|Mevr|Avv|Dott|Ing|Sig|D|Dña|Sr|Sra|Srta)(?:\.|\b)[ \t\xA0]+((?:(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)[ \t\xA0]+){0,2}(?:\p{Lu}\.(?:[ \t\xA0]*\p{Lu}\.)*|(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}[\p{L}'’–-]+)(?:[ \t\xA0]+(?:\p{Lu}\.|(?:(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)[ \t\xA0]+){0,2}(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}[\p{L}'’–-]+)){0,3})(?![‘'’–-][\p{L}0-9])(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]
|
|
301
|
+
{ name: 'Names with Honorifics', type: 'NAME', isContextName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?:Kollege|Kollegin|Instandhalter|Instandhalterin|Disponent|Disponentin|Werkstudent|Werkstudentin|Lagerleiter|Lagerleiterin|Arbeitsvorbereiter|Arbeitsvorbereiterin|Qualitätsprüfer|Qualitätsprüferin|Dott\.ssa|Sig\.ra|Mr|Mrs|Ms|Miss|Dr|Prof|Hon|Rev|Judge|Atty|Doctor|Professor|Sir|Lord|Lady|Dame|Herr|Frau|Rechtsanwalt|Rechtsanwältin|Notar|Schichtleiter|Schichtleiterin|Schichtführer|Schichtführerin|Teamleiter(?:in)?\s+(?:Produktion|Entwicklung|Qualität|Vertrieb|Logistik|Fertigung)|Teamleiter|Teamleiterin|Einrichter|Einrichterin|Laborant|Laborantin|Betriebsratssprecher|Betriebsratssprecherin|Meister|Meisterin|Geschäftsführer|Geschäftsführerin|Projektleiter|Projektleiterin|Abteilungsleiter|Abteilungsleiterin|Bereichsleiter|Bereichsleiterin|Betriebsleiter|Betriebsleiterin|Werkleiter|Werkleiterin|Produktionsleiter|Produktionsleiterin|Qualitätsleiter|Qualitätsleiterin|Assistent|Assistentin|Ansprechpartner|Ansprechpartnerin|Prüfer|Prüferin|Monteur|Monteurin|Inbetriebnehmer|Inbetriebnehmerin|Vorstand|Mme|Mlle|Me|Monsieur|Madame|Mademoiselle|Maître|Don|Doña|Señor|Señora|Avvocato|Dottore|Dottoressa|Ingegnere|Signor|Signora|Dhr|Mevr|Avv|Dott|Ing|Sig|D|Dña|Sr|Sra|Srta)(?:\.|\b)[ \t\xA0]+((?:(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)[ \t\xA0]+){0,2}(?:\p{Lu}\.(?:[ \t\xA0]*\p{Lu}\.)*|(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}[\p{L}'’–-]+)(?:[ \t\xA0]+(?:\p{Lu}\.|(?:(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)[ \t\xA0]+){0,2}(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}[\p{L}'’–-]+)){0,3})(?![‘'’–-][\p{L}0-9])(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*[:$€£¥₪₽₹])/gu },
|
|
218
302
|
// Dutch / European Inverted Format (e.g. "Ruiter, J. de", "Berg, S. van den", "Gameren, P. van")
|
|
219
303
|
{ name: 'Dutch Inverted Administrative Name', type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}[\p{Ll}'’–-]+(?:-[\p{Lu}\p{Ll}'’–-]+)?,[ \t\xA0]+(?:\p{Lu}\.(?:[ \t\xA0]*\p{Lu}\.)*|\p{Lu}[\p{Ll}'’–-]+)[ \t\xA0]+(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)(?=[^\p{L}\p{N}_]|$)/gu },
|
|
220
304
|
// European & Initial-Prefixed Names (e.g. "J. de Ruiter", "P. van Gameren", "J.A. van der Meer", "M. de Jong", "J. Smith")
|
|
221
|
-
{ type: 'NAME', isAggressiveName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?<!\b(?:Fed|Federal|State|Local|U\.?S\.?)\.?\s+)(?:\p{Lu}\.(?:[ \t\xA0]*\p{Lu}\.)*)(?!\s*(?:Civ|Crim|App|Evid|Bankr|Pro|Proc|Jud)\b)[ \t\xA0]+(?:(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)[ \t\xA0]+){0,2}(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}
|
|
305
|
+
{ type: 'NAME', isAggressiveName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?<!\b(?:Fed|Federal|State|Local|U\.?S\.?)\.?\s+)(?:\p{Lu}\.(?:[ \t\xA0]*\p{Lu}\.)*)(?!\s*(?:Civ|Crim|App|Evid|Bankr|Pro|Proc|Jud)\b)[ \t\xA0]+(?:(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)[ \t\xA0]+){0,2}(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}\p{Ll}+(?:['’]\p{L}+)*(?:-\p{Lu}\p{Ll}+(?:['’]\p{L}+)*)*)(?:'s)?(?![‘'’–-][\p{L}0-9])(?![&/]\p{L})(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*[:$€£¥₪₽₹])/gu },
|
|
222
306
|
// Generalized Name Detection (First [Middle] Last) — supporting European particles, apostrophes (d', l', Dell', D', O', M'), Celtic (Mc, Mac, Fitz), multi-hyphens, and Spanish conjunctions
|
|
223
|
-
{ type: 'NAME', isAggressiveName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?!(?:Brief|Dossier|Schreiben|Bericht|Akte|Urteil|Vertrag|Notiz|Auftrag|Fertigungsauftrag|Lieferschein|Bestellung|Rechnung|Ticket|Rapport|Document|Lettre|Acta|Sentencia)[ \t\xA0]+(?:von|van|de|du|di|da|del)\b)(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}
|
|
307
|
+
{ type: 'NAME', isAggressiveName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?!(?:Brief|Dossier|Schreiben|Bericht|Akte|Urteil|Vertrag|Notiz|Auftrag|Fertigungsauftrag|Lieferschein|Bestellung|Rechnung|Ticket|Rapport|Document|Lettre|Acta|Sentencia)[ \t\xA0]+(?:von|van|de|du|di|da|del)\b)(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}\p{Ll}*(?:['’]\p{L}+)*(?:-\p{Lu}\p{Ll}*(?:['’]\p{L}+)*)*)(?:[ \t\xA0]+(?:(?:von[ \t\xA0]+und[ \t\xA0]+zu|von[ \t\xA0]+der|van[ \t\xA0]+de(?:n|r)?|van[ \t\xA0]+['’]t|in[ \t\xA0]+['’]t|de[ \t\xA0]+l['’]|de[ \t\xA0]+la[ \t\xA0]+(?:los|las)?|de[ \t\xA0]+(?:la|las|los)|['’]t|(?:Dell|Dall|Sant|[DdLlOoMm])['’]|van|von|zu|vom|auf|de|di|da|do|dos|das|la|le|del|dels|du|der|den|te|ten|ter|af|av)|(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}\p{Ll}*(?:['’]\p{L}+)*(?:-\p{Lu}\p{Ll}*(?:['’]\p{L}+)*)*)|\p{Lu}\.?)){0,2}[ \t\xA0]+(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}\p{Ll}*(?:['’]\p{L}+)*(?:-\p{Lu}\p{Ll}*(?:['’]\p{L}+)*)*)(?:[ \t\xA0]+(?:y|i)[ \t\xA0]+(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}\p{Ll}*(?:['’]\p{L}+)*(?:-\p{Lu}\p{Ll}*(?:['’]\p{L}+)*)*))?(?:'s)?(?![‘'’–-][\p{L}0-9])(?![&/]\p{L})(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*[:$€£¥₪₽₹])/gu },
|
|
224
308
|
// Payroll & Inverted Format Names (e.g. "BARKER, KELLY", "Vance-Soto, Eleanor", "Lefèvre-Saint-Germain, Hélène")
|
|
225
309
|
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}[\p{L}'’–-]+(?:-[\p{Lu}\p{Ll}'’–-]+)?,[ \t\xA0]+(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}[\p{L}'’–-]+)(?:[ \t\xA0]+\p{Lu}\.?(?!\p{L})|[ \t\xA0]+(?:(?:(?:Dell|Dall|Sant|[DdLlOoMm])['’]|(?:Mc|Mac|Fitz))?\p{Lu}[\p{L}'’–-]+))*(?=[^\p{L}\p{N}_]|$)/gu },
|
|
226
310
|
// All-Caps Names (2–3 words, supporting single-letter middle initial e.g. "KELLY M BARKER", "JOHN M BARKER")
|
|
227
|
-
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:[ \t\xA0]+(?:\p{Lu}\.?|[A-Z][a-z]+))?[ \t\xA0]+\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]
|
|
311
|
+
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:[ \t\xA0]+(?:\p{Lu}\.?|[A-Z][a-z]+))?[ \t\xA0]+\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*[:$€£¥₪₽₹])/gu },
|
|
228
312
|
// ALL-CAPS first + middle initial(s) with optional spaces + ALL-CAPS last name
|
|
229
|
-
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:[ \t\xA0]*\p{Lu}\.)+[ \t\xA0]*\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]
|
|
313
|
+
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:[ \t\xA0]*\p{Lu}\.)+[ \t\xA0]*\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*[:$€£¥₪₽₹])/gu },
|
|
230
314
|
// ALL-CAPS first name + optional middle initial(s) with optional spaces + Mixed-Case last name
|
|
231
|
-
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:(?:[ \t\xA0]*\p{Lu}\.)+[ \t\xA0]*|[ \t\xA0]+)(?:\p{Lu}\p{Ll}[\p{Ll}'-]*|\p{Lu}[\p{Ll}'-]*[\p{Lu}'-][\p{Ll}'-]*)(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]
|
|
315
|
+
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:(?:[ \t\xA0]*\p{Lu}\.)+[ \t\xA0]*|[ \t\xA0]+)(?:\p{Lu}\p{Ll}[\p{Ll}'-]*|\p{Lu}[\p{Ll}'-]*[\p{Lu}'-][\p{Ll}'-]*)(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*[:$€£¥₪₽₹])/gu },
|
|
232
316
|
// Names with Quoted or Parenthetical Nicknames (e.g. Judith "Judy" Diaz, Robert (Bob) Smith)
|
|
233
|
-
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])(?:\p{Lu}[\p{Ll}'-]+)[ \t\xA0]+(?:"[\p{Lu}\p{Ll}'-]+"|'[\p{Lu}\p{Ll}'-]+'|[“‘][\p{Lu}\p{Ll}'-]+[”’]|\([\p{Lu}\p{Ll}'-]+\))[ \t\xA0]+(?:\p{Lu}[\p{Ll}'-]+)(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]
|
|
317
|
+
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])(?:\p{Lu}[\p{Ll}'-]+)[ \t\xA0]+(?:"[\p{Lu}\p{Ll}'-]+"|'[\p{Lu}\p{Ll}'-]+'|[“‘][\p{Lu}\p{Ll}'-]+[”’]|\([\p{Lu}\p{Ll}'-]+\))[ \t\xA0]+(?:\p{Lu}[\p{Ll}'-]+)(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*[:$€£¥₪₽₹])/gu },
|
|
234
318
|
|
|
235
319
|
// W-2 Box c Employer Block (Name, Address, and Zip Code)
|
|
236
320
|
{ type: 'NAME', isContextName: true, regex: /(?:(?:\bBox\s+c\b|\bc\.\s*|\bc\s+(?=Employer))\s*(?:Employer(?:'s)?\s*)?(?:name[,\s]+address[,\s]+and\s+ZIP\s+code|name)?|(?:Employer(?:'s)?\s+name[,\s]+address[,\s]+and\s+ZIP\s+code))[\s:#]*([A-Za-z0-9&., \t\xA0'-]{2,45}?)(?=\r?\n|$|\s{3,}|\t|EIN|FEIN|Box|\d+\b|Wages|Federal|Social|Medicare)/gi },
|
|
@@ -240,6 +324,8 @@ let REGEX_RULES = [
|
|
|
240
324
|
{ type: 'NAME', isContextName: true, regex: /(?:(?:Your|Employee(?:'s)?|Borrower(?:'s)?|Co-Borrower(?:'s)?|Applicant(?:'s)?|Candidate(?:'s)?|Worker(?:'s)?|Taxpayer(?:'s)?|Spouse(?:'s)?|Person(?:'s)?)\s+)?(?:First\s+name(?:\s+(?:and|&)\s+(?:middle\s+)?initial)?|Given\s+name)[\s:#]+(?:\b|\b\s*)([A-Za-z0-9.\s'-]{2,30}?)(?=\r?\n|$|\s{3,}|\t|Last|Surname|Family|Suff|Box|Address|SSN|EIN)/gi },
|
|
241
325
|
// Contextual Last Names (Last name, Surname, Family name)
|
|
242
326
|
{ type: 'NAME', isContextName: true, regex: /(?:(?:Your|Employee(?:'s)?|Borrower(?:'s)?|Co-Borrower(?:'s)?|Applicant(?:'s)?|Candidate(?:'s)?|Worker(?:'s)?|Taxpayer(?:'s)?|Spouse(?:'s)?|Person(?:'s)?)\s+)?(?:Last\s+name|Surname|Family\s+name)[\s:#]+(?:\b|\b\s*)([A-Za-z'-]{2,30})/gi },
|
|
327
|
+
// JSON / API Key-Value Single & Multi-Token Names ("firstName": "Sarah", "lastName": "Connor")
|
|
328
|
+
{ type: 'NAME', isContextName: true, regex: /(?<=["'](?:firstName|first_name|lastName|last_name|middleName|middle_name|givenName|given_name|familyName|family_name|surname|fullName|full_name|customerName|customer_name|clientName|client_name|patientName|patient_name|employeeName|employee_name|contactName|contact_name)["']\s*:\s*["'])([A-Z\p{Lu}][\p{L}'’.-]{1,35}(?:[ \t\xA0]+[A-Z\p{Lu}][\p{L}'’.-]{1,35}){0,3})(?=["'])/gu },
|
|
243
329
|
// Contextual General Names (Employee, Principal Investigator, Physician, Doctor, etc.)
|
|
244
330
|
{ type: 'NAME', isContextName: true, regex: /(?:(?:Employee|Employer|Borrower|Co-Borrower|Applicant|Candidate|Worker|Taxpayer|Spouse|Client|Customer|Patient|Claimant|Insured|Tenant|Landlord|Buyer|Seller|Plaintiff|Defendant|Testator|Author|(?:Subject\s+)?Personnel)\s+(?:Name|Full\s+Name)|(?:Principal\s+Investigator|Investigator|Physician|Doctor|Supervisor|Reporting\s+To|Prepared\s+By|Attention|Attn|(?<!Emergency\s+|ICE\s+)Contact(?:\s+Person)?|Author)(?:\s+Name)?|(?:Employee|Employer|Borrower|Client|Customer|Patient|Claimant|Insured|Doctor|Attn|Signatory|Witness|Tenant|Landlord|Buyer|Seller|Plaintiff|Defendant|Author|(?:Subject\s+)?Personnel)\s*[:=#])[:\s#|]*(?:\b|\b\s*)([A-Z\p{Lu}][A-Za-z0-9&.,\s'"“”()-]{1,35}?)(?=\r?\n|$|\s{3,}|\t|Employee|Employer|Address|Phone|SSN|EIN|FEIN|Date|Pay|Rate|Tax|W-2|OMB|Copy|Box|Status|\|)/giu },
|
|
245
331
|
// Contextual Nicknames & Preferred Names (e.g. "Nickname: Judy", "Preferred Name: Alex", "AKA: Bob", "Goes by: Sam")
|
|
@@ -360,11 +446,13 @@ let PROFILE_RULES = {
|
|
|
360
446
|
{ type: 'ID', regex: /\b(?:CRD|CIK|Advisor\s*ID|Broker\s*ID)[:\s#]*(\d{5,10})\b/gi },
|
|
361
447
|
{ type: 'ID', regex: /\b(?:LEI|LEGAL[\s-]ENTITY[\s-]IDENTIFIER)[:\s#-]*[0-9A-Z]{20}\b/gi },
|
|
362
448
|
{ type: 'ID', regex: /\bBBG[0-9A-Z]{9}\b/g },
|
|
363
|
-
{ type: 'FINANCIAL', regex: /(?<=\b(?:Settlement(?:\s+Amount)?|Wire(?:\s+(?:Transfer|Amount))?|Direct\s+Wire|Transaction(?:\s+Amount)?|Payment(?:\s+Amount)?)[ \t:]+)(?:(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹]))/gi },
|
|
364
|
-
{ type: 'FINANCIAL', regex: /(?<=(?:^|[\r\n\t.;])\s*(?<!\b(?:Trade(?:\s+execution)?|Net|Gross|Base|Loan|Transfer)\s+)(?:Wire(?:\s+(?:Transfer|Amount))?|Direct\s+Wire|Balance|Deposit|Withdrawal|Settlement|Principal|Interest|Remittance|Payout|(?:Capital\s+|Annual\s+)?Distribution(?:s)?|Transaction(?:\s+Amount)?|Payment(?:\s+Amount)?|Total(?:\s+Due)?|Amount(?:\s+Due)?)[:\s]+)(?:(?:\((?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]+[KMB]?\)|(?:[$€£¥₪₽₹]\s*)\([0-9,.'’\u2018\u2019]+[KMB]?\))|(?:[-−](?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\b|(?:[$€£¥₪₽₹]\s*)[-−][0-9,.'’\u2018\u2019]*\d[KMB]?\b)|(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹]))|[0-9,.'’]{3,}\b)/gi },
|
|
365
|
-
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:
|
|
449
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:Settlement(?:\s+Amount)?|Wire(?:\s+(?:Transfer|Amount))?|Direct\s+Wire|Transaction(?:\s+Amount)?|Payment(?:\s+Amount)?)[ \t:]+)(?:(?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])|(?:USD|EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s?)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])))/gi },
|
|
450
|
+
{ type: 'FINANCIAL', regex: /(?<=(?:^|[\r\n\t.;])\s*(?<!\b(?:Trade(?:\s+execution)?|Net|Gross|Base|Loan|Transfer)\s+)(?:Wire(?:\s+(?:Transfer|Amount))?|Direct\s+Wire|Balance|Deposit|Withdrawal|Settlement|Principal|Interest|Remittance|Payout|(?:Capital\s+|Annual\s+)?Distribution(?:s)?|Transaction(?:\s+Amount)?|Payment(?:\s+Amount)?|Total(?:\s+Due)?|Amount(?:\s+Due)?)[:\s]+)(?:(?:\((?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)?[0-9,.'’\u2018\u2019]+[KMB]?\)|(?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)\([0-9,.'’\u2018\u2019]+[KMB]?\))|(?:[-−](?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\b|(?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)[-−][0-9,.'’\u2018\u2019]*\d[KMB]?\b)|(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s*|(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])))|[0-9,.'’]{3,}\b)/gi },
|
|
451
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s*|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])\s*)(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?(?:\s*(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))?\b|\b(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?\s*(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))/gi },
|
|
452
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\$\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\s*\bUSD\b|\bUSD\s*\$?[0-9,.'’\u2018\u2019]*\d[KMB]?\b)/gi },
|
|
453
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:(?:ending|opening|current|available|ledger|account)\s+)?(?:balance|wire|settlement|distribution|withdrawal|payout|remittance)\s*(?:was|is|of|[:=])\s*)(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi },
|
|
366
454
|
// Corporate Financial Performance, P&L Statements, Balance Sheets & Earnings
|
|
367
|
-
{ type: 'FINANCIAL', regex: /(?<=\b(?<!\b(?:EV|Debt|Net\s+Debt)\/)(?:Revenue|Total\s+Revenue|Sales\s+Revenue|Cost\s+of\s+Goods(?:\s+Sold)?|COGS|Gross\s+Profit|Operating\s+Expenses?|OpEx|Operating\s+Income(?:\s*\([^)]*\))?|Operating\s+Loss|Net\s+Income(?:\s*[/()]*\s*Loss)?|Net\s+Loss|Foreign\s+Exchange(?:\s+Loss)?|FX\s+Loss|Retained\s+Earnings|Total\s+Equity|Shareholders?'?\s+Equity|Total\s+Assets|Total\s+Liabilities|Accounts\s+Payable|Accounts\s+Receivable|Cash|Cash\s+Flow|Free\s+Cash\s+Flow|Capital\s+Expenditures?|CapEx|Dividends?|EBITDA|EBIT|Balance|Loss|Profit)[:|\s]+)(?:(?:\((?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]+[KMB]?\)|(?:[$€£¥₪₽₹]\s*)\([0-9,.'’\u2018\u2019]+[KMB]?\))|(?:[-−](?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\b|(?:[$€£¥₪₽₹]\s*)[-−][0-9,.'’\u2018\u2019]*\d[KMB]?\b)|(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹]))|[0-9,.'’]*\d\b)(?![ \t\xA0]*(?:%|[xX]\b|times\b|bps\b))/gi },
|
|
455
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?<!\b(?:EV|Debt|Net\s+Debt)\/)(?:Revenue|Total\s+Revenue|Sales\s+Revenue|Cost\s+of\s+Goods(?:\s+Sold)?|COGS|Gross\s+Profit|Operating\s+Expenses?|OpEx|Operating\s+Income(?:\s*\([^)]*\))?|Operating\s+Loss|Net\s+Income(?:\s*[/()]*\s*Loss)?|Net\s+Loss|Foreign\s+Exchange(?:\s+Loss)?|FX\s+Loss|Retained\s+Earnings|Total\s+Equity|Shareholders?'?\s+Equity|Total\s+Assets|Total\s+Liabilities|Accounts\s+Payable|Accounts\s+Receivable|Cash|Cash\s+Flow|Free\s+Cash\s+Flow|Capital\s+Expenditures?|CapEx|Dividends?|EBITDA|EBIT|Balance|Loss|Profit)[:|\s]+)(?:(?:\((?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)?[0-9,.'’\u2018\u2019]+[KMB]?\)|(?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)\([0-9,.'’\u2018\u2019]+[KMB]?\))|(?:[-−](?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\b|(?:(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)[-−][0-9,.'’\u2018\u2019]*\d[KMB]?\b)|(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s*|(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])\s*)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[$€£¥₪₽₹])))|[0-9,.'’]*\d\b)(?![ \t\xA0]*(?:%|[xX]\b|times\b|bps\b))/gi },
|
|
368
456
|
// Interbank Wire Transcripts & Payment Messaging
|
|
369
457
|
{ type: 'FINANCIAL', regex: /\b(?:(?:SWIFT(?:\s+MT\d{3})?\s+)?(?:Field\s+2[01]|F2[01])(?:\s+Transaction\s+Reference)?|TRN|Transaction\s+Reference(?:\s+Number)?|SWIFT\s+Ref)[:\s#-]+([A-Za-z0-9\/-]{8,30})\b/gi },
|
|
370
458
|
{ type: 'FINANCIAL', regex: /\bFT\d{10,14}\b/gi },
|
|
@@ -385,11 +473,18 @@ let PROFILE_RULES = {
|
|
|
385
473
|
{ type: 'ID', regex: /\b(?:Lockbox|DACA|Deposit\s+Account\s+Control\s+Agreement|Blocked\s+Account(?:\s+Agreement)?)[ \t\xA0]*(?:Account|ID|Ref|No\.?|#)?[ \t\xA0]*[:#-][ \t\xA0]*([A-Za-z0-9-]{4,25})\b/gi }
|
|
386
474
|
],
|
|
387
475
|
medical: [
|
|
388
|
-
{ type: 'NAME', isContextName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?:PATIENT|Pt\.?|LEGAL\s+GUARDIAN(?:\/PROXY)?|PROXY|EMERGENCY\s+CONTACT|(?:ATTENDING|CONSULTING|ADMITTING|REFERRING|TREATING|ORDERING|PRIMARY\s+CARE|RESIDENT|STAFF|SUPERVISING|EMERGENCY)\s+(?:PHYSICIAN|PROVIDER|DOCTOR|SURGEON|CLINICIAN|SPECIALIST|NEUROLOGIST|CARDIOLOGIST|ONCOLOGIST|RADIOLOGIST|PATHOLOGIST|PSYCHIATRIST|PEDIATRICIAN|ANESTHESIOLOGIST|HOSPITALIST|PCP)|ATTENDING|SURGEON|PHYSICIAN|PROVIDER|CLINICIAN|PCP|(?:CLINICAL\s+)?SCRIBE|TRANSCRIBED\s+BY|DICTATED\s+BY|NURSE\s+PRACTITIONER|PHYSICIAN\s+ASSISTANT|REGISTERED\s+NURSE|SUBSCRIBER|GUARDIAN)\s*[:#|]?\s*(?!\b(?:NPI|MRN|DOB|ID|DATE|RECORD|PHONE)\b)(?:(?:Dr
|
|
476
|
+
{ type: 'NAME', isContextName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?:PATIENT|Pt\.?|PACIENTE|M[ÉE]DICO(?:\s+(?:RESPONS[ÁA]VEL|ASSISTENTE|SOLICITANTE))?|CIRURGI[ÃA]O|OFTALMOLOGISTA|DOUTOR(?:A)?|RESPONS[ÁA]VEL(?:\s+LEGAL)?|LEGAL\s+GUARDIAN(?:\/PROXY)?|PROXY|EMERGENCY\s+CONTACT|(?:ATTENDING|CONSULTING|ADMITTING|REFERRING|TREATING|ORDERING|PRIMARY\s+CARE|RESIDENT|STAFF|SUPERVISING|EMERGENCY)\s+(?:PHYSICIAN|PROVIDER|DOCTOR|SURGEON|CLINICIAN|SPECIALIST|NEUROLOGIST|CARDIOLOGIST|ONCOLOGIST|RADIOLOGIST|PATHOLOGIST|PSYCHIATRIST|PEDIATRICIAN|ANESTHESIOLOGIST|HOSPITALIST|PCP)|ATTENDING|SURGEON|PHYSICIAN|PROVIDER|CLINICIAN|PCP|(?:CLINICAL\s+)?SCRIBE|TRANSCRIBED\s+BY|DICTATED\s+BY|NURSE\s+PRACTITIONER|PHYSICIAN\s+ASSISTANT|REGISTERED\s+NURSE|SUBSCRIBER|GUARDIAN)\s*[:#|]?\s*(?!\b(?:NPI|MRN|DOB|ID|DATE|RECORD|PHONE|CPF|CNS|CRM)\b)(?:(?:Dr\.?a?|Doctor|Doutor(?:a)?|Prof\.?a?|Professor|Mr|Mrs|Ms|Sr\.?a?)\.?\s+)?((?:(?:d['’]|l['’]|(?:(?:van|von|de|di|da|do|dos|das|la|le|del|dels|du|der|den|ten|ter|af|av)\s+)+)\s*)?\p{Lu}[\p{L}'’–-]*(?:-[\p{Lu}\p{Ll}'’–-]+)*(?:,\s+(?:(?:d['’]|l['’])?\p{Lu}[\p{L}'’–-]+)(?:\s+\p{Lu}\.?)?(?:,\s*(?:Jr\.?|Sr\.?|Filho|Neto|Sobrinho|III|IV|II))?|\s+(?:(?:van|von|de|di|da|do|dos|das|la|le|del|du|der|d['’]|l['’]|de\s+la|de\s+los|von\s+der)\s+)?(?:(?:\p{Lu}\.?\s+)?(?:d['’]|l['’])?\p{Lu}[\p{L}'’–-]*(?:-[\p{Lu}\p{Ll}'’–-]+)*))(?:\s+(?:y|i|e)\s+(?:(?:d['’]|l['’])?\p{Lu}[\p{L}'’–-]+))?)(?=[ \t\xA0]*,?[ \t\xA0]*(?:(?:MD|DO|MBBS|PhD|MSN|BSN|RN|NP|FNP|DNP|PA-C|PA|DDS|DMD|PharmD|OD|DPT|DC|CRNA|CNM|FACS|FAAP|FACC|FACP|CRM|RQE)\b|[^\p{L}\p{N}]|$))/giu },
|
|
389
477
|
// HL7 v2 PID-5 Caret-Delimited Patient / Provider Names (e.g. "Guillermo^Maricela^C", "Vance-Soto^Eleanor^M")
|
|
390
478
|
{ type: 'NAME', isContextName: true, isHL7Name: true, regex: /\b[A-Za-z'’-]{2,}\^[A-Za-z'’-]{2,}(?:\^[A-Za-z'’.-]+){0,4}\b/g },
|
|
391
479
|
// HL7 v2 Segment Delimited Dates (YYYYMMDD in PID-7, MSH-7, etc. e.g. "||19820412|F")
|
|
392
480
|
{ type: 'DATE', regex: /(?<=[|:])(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])(?=[|:\s])/g },
|
|
481
|
+
// Brazil SUS / Cartão Nacional de Saúde (CNS - 15 digits starting with 1, 2, 7, 8, or 9)
|
|
482
|
+
{ type: 'PHI', regex: /\b(?:(?:CNS|Cart[ãa]o\s+(?:Nacional\s+de\s+Sa[úu]de|SUS))[:\s#.-]*([12789]\d{2}[ \t.-]?\d{4}[ \t.-]?\d{4}[ \t.-]?\d{4})|([12789]\d{2}[ \t.-]\d{4}[ \t.-]\d{4}[ \t.-]\d{4}))\b/gi },
|
|
483
|
+
// Brazil Clinical Council Registrations (CRM, COREN, CRO, CRF, CREFITO, CRP, CRN, RQE)
|
|
484
|
+
{ type: 'ID', regex: /\b(?:CRM|COREN|CRO|CRF|CREFITO|CRP|CRN|RQE)(?:[-/\s]+(?:AC|AL|AP|AM|BA|CE|DF|ES|GO|MA|MT|MS|MG|PA|PB|PR|PE|PI|RJ|RN|RS|RO|RR|SC|SP|SE|TO))?(?:\s*(?:n[º°o]?|#))?[:\s#.-]+(\d{3,10}(?:[-/][A-Za-z]{1,3})?)\b/gi },
|
|
485
|
+
{ type: 'PHI', regex: /\b(?:Prontu[áa]rio|Atendimento|Registro\s+Hospitalar|Guia\s+TISS|Carteirinha(?:\s+do\s+Conv[êe]nio)?)[:\s#.-]+([A-Za-z0-9./_-]{3,25})\b/gi },
|
|
486
|
+
{ type: 'PHI', regex: /\b(?:Accession(?:\s*(?:No\.?|Number|#|ID))?|ACC)\s*[:#=-]+\s*([A-Za-z0-9._/-]{4,25})\b/gi },
|
|
487
|
+
{ type: 'PHI', regex: /\b(?:(?:Study|Series|SOP)\s*Instance\s*UID|(?:Study|Series|SOP)InstanceUID|DICOM\s+UID)\s*[:=#-]*\s*((?:1\.2\.840|2\.25)\.\d+(?:\.\d+){4,15})\b|\b(?:1\.2\.840\.10008|1\.2\.840\.113619)\.\d+(?:\.\d+){3,15}\b/gi },
|
|
393
488
|
{ type: 'PHI', regex: /\b(?:MRN|Patient|Medical\s+Record|EHR|Subject|Participant|Screening|Randomization|Cohort|Site)\s*(?:ID|Number|No\.?|#)?[:\s#.]+([A-Za-z0-9\/_-]+)/gi },
|
|
394
489
|
{ type: 'PHI', regex: /\b(?:SUBJ|PARTICIPANT|RAND|SCR)[-_][A-Za-z0-9\/_-]{3,}\b/gi },
|
|
395
490
|
{ type: 'DATE', regex: /\b(?:DOB|Date of Birth|BIRTHDAY)[\s:]+([0-9./-]{6,10})\b/gi },
|
|
@@ -1192,7 +1287,9 @@ let PROFILE_RULES = {
|
|
|
1192
1287
|
{ type: 'ID', regex: /\bCRD\s*#?\s*\d{4,8}\b/gi },
|
|
1193
1288
|
{ type: 'FINANCIAL', regex: /(?<=\b(?:(?:Capital\s+|Annual\s+)?(?:Distribution|Withdrawal)s?|RMD|Required\s+Minimum\s+Distribution)[:\s]+)(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi },
|
|
1194
1289
|
{ type: 'FINANCIAL', regex: /(?<=\b(?:Portfolio(?:\s+[Vv]alue)?|Market\s+Value|Net\s+Worth|AUM|Total\s+Assets|Cash\s+Balance|Account\s+Value|Capital\s+Gains?|Unrealized\s+(?:Gain|Loss)|Realized\s+(?:Gain|Loss)|Dividend\s+Income)[:\s]+)(?:(?:\((?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]+[KMB]?\)|(?:[$€£¥₪₽₹]\s*)\([0-9,.'’\u2018\u2019]+[KMB]?\))|(?:[-−](?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\b|(?:[$€£¥₪₽₹]\s*)[-−][0-9,.'’\u2018\u2019]*\d[KMB]?\b)|(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹]))|[0-9,.'’]{3,}\b)/gi },
|
|
1195
|
-
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:
|
|
1290
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s*|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])\s*)(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?(?:\s*(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))?\b|\b(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?\s*(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))/gi },
|
|
1291
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\$\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\s*\bUSD\b|\bUSD\s*\$?[0-9,.'’\u2018\u2019]*\d[KMB]?\b)/gi },
|
|
1292
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:(?:ending|opening|current|available|ledger|account)\s+)?(?:balance|wire|settlement|distribution|withdrawal|payout|remittance)\s*(?:was|is|of|[:=])\s*)[$€£¥₪₽₹]\s*[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi },
|
|
1196
1293
|
{ type: 'FINANCIAL', regex: /\b(?:Roth\s+)?(?:IRA|401k|401\(k\)|403b|403\(b\)|SEP|SIMPLE)\s*(?:Account|Acct|Plan)?\s*(?:(?:No\.?|Number|#)[:\s#]*|[:#]\s*)([A-Z0-9-]{4,20})\b/gi },
|
|
1197
1294
|
{ type: 'ID', regex: /\bCUSIP[:\s#]*([0-9A-Z]{9})\b/gi },
|
|
1198
1295
|
{ type: 'ID', regex: /\bISIN[:\s#]*([A-Z]{2}[0-9A-Z]{9}[0-9])\b/gi },
|
|
@@ -1280,7 +1377,9 @@ let PROFILE_RULES = {
|
|
|
1280
1377
|
},
|
|
1281
1378
|
// Existing core insurance patterns
|
|
1282
1379
|
{ type: 'FINANCIAL', regex: /(?<=\b(?:Loss|Claim\s+Amount|Claim\s+Settlement|Settlement|(?<!\b(?:Case|Outstanding|IBNR|Loss)\s+)Reserve|Indemnity)[:\s]+)(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi },
|
|
1283
|
-
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:
|
|
1380
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s*|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])\s*)(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?(?:\s*(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))?\b|\b(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?\s*(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))/gi },
|
|
1381
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\$\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\s*\bUSD\b|\bUSD\s*\$?[0-9,.'’\u2018\u2019]*\d[KMB]?\b)/gi },
|
|
1382
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:(?:ending|opening|current|available|ledger|account)\s+)?(?:balance|wire|settlement|distribution|withdrawal|payout|remittance)\s*(?:was|is|of|[:=])\s*)[$€£¥₪₽₹]\s*[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi },
|
|
1284
1383
|
{ type: 'ID', regex: /\b(?:(?:Assigned\s+)?Adjuster\s+(?:ID|No)|Claim\s+Rep(?:\.|resentative)?)[:\s#]*[-A-Z0-9]{4,15}\b/gi },
|
|
1285
1384
|
{ type: 'ID', regex: /\bNAIC(?:\s+(?:Company\s+)?(?:Code|CoCode|No\.?|Number|#))?[:\s#]*(\d{5})\b/gi },
|
|
1286
1385
|
{ type: 'FINANCIAL', regex: /(?<=\b(?:Deductible|Premium|Coverage\s+Amount)[:\s]+)(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi },
|
|
@@ -1314,7 +1413,9 @@ let PROFILE_RULES = {
|
|
|
1314
1413
|
{ type: 'ID', regex: /\b(?:Invoice|Inv|Purchase\s+Order|PO|Bill|Check|Voucher|Remittance)\s*(?:Number|Num|No\.?|#)?[:\s#]+([A-Za-z0-9_-]{4,25})\b/gi },
|
|
1315
1414
|
{ type: 'FINANCIAL', regex: /(?<=\b(?<!\b(?:EV|Debt|Net\s+Debt)\/)(?:Invoice(?:\s+Total)?|Amount\s+Due|Total(?:\s+Due)?|Payment(?:\s+Amount)?|Ledger\s+Balance|Credit|Debit|Net\s+Amount|Total\s+Paid|Billed|Remittance|Total\s+Revenue|Revenue|Cost\s+of\s+Goods(?:\s+Sold)?|COGS|Gross\s+Profit|Operating\s+Expenses?|OpEx|Operating\s+Income(?:\s*\([^)]*\))?|Operating\s+Loss|Net\s+Income(?:\s*[/()]*\s*Loss)?|Net\s+Loss|Foreign\s+Exchange(?:\s+Loss)?|FX\s+Loss|Retained\s+Earnings|Total\s+Equity|Shareholders?'?\s+Equity|Total\s+Assets|Total\s+Liabilities|Accounts\s+Payable|Accounts\s+Receivable|Cash|Cash\s+Flow|Free\s+Cash\s+Flow|Capital\s+Expenditures?|CapEx|Dividends?|(?:Capital\s+|Annual\s+)?Distribution(?:s)?|Withdrawal(?:s)?|Settlement(?:s)?|Sales\s+Revenue|EBITDA|EBIT|Balance|Loss|Profit)[:|\s]+)(?:(?:\((?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]+[KMB]?\)|(?:[$€£¥₪₽₹]\s*)\([0-9,.'’\u2018\u2019]+[KMB]?\))|(?:[-−](?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\b|(?:[$€£¥₪₽₹]\s*)[-−][0-9,.'’\u2018\u2019]*\d[KMB]?\b)|(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹]))|[0-9,.'’]*\d\b)(?![ \t\xA0]*(?:%|[xX]\b|times\b|bps\b))/gi },
|
|
1316
1415
|
{ type: 'FINANCIAL', regex: /(?<=\|\s*)(?:(?:\((?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]+[KMB]?\)|(?:[$€£¥₪₽₹]\s*)\([0-9,.'’\u2018\u2019]+[KMB]?\))|(?:[-−](?:[$€£¥₪₽₹]\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\b|(?:[$€£¥₪₽₹]\s*)[-−][0-9,.'’\u2018\u2019]*\d[KMB]?\b)|(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’\u2018\u2019]*\d[KMB]?\b|\b\d[0-9,.'’\u2018\u2019]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹])))(?=\s*\|)/gi },
|
|
1317
|
-
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:
|
|
1416
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s*|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])\s*)(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?(?:\s*(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))?\b|\b(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?\s*(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))/gi },
|
|
1417
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\$\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\s*\bUSD\b|\bUSD\s*\$?[0-9,.'’\u2018\u2019]*\d[KMB]?\b)/gi },
|
|
1418
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:(?:ending|opening|current|available|ledger|account)\s+)?(?:balance|wire|settlement|distribution|withdrawal|payout|remittance)\s*(?:was|is|of|[:=])\s*)[$€£¥₪₽₹]\s*[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi }
|
|
1318
1419
|
],
|
|
1319
1420
|
pharma: [
|
|
1320
1421
|
// Contextual Clinical, Regulatory & Pharmacovigilance Personnel
|
|
@@ -1598,14 +1699,16 @@ let PROFILE_RULES = {
|
|
|
1598
1699
|
{ type: 'ID', regex: /\b(?:Ineligible\s+AR|Eligible\s+AR|Collateral\s+Account)(?:\s+(?:Account|Acct|ID|Ref|No\.?|Number|#))*\s*[:#-]\s*([A-Za-z0-9-]{4,20})\b/gi },
|
|
1599
1700
|
{ type: 'ID', regex: /\b(?:Merchant\s+Cash\s+Advance|MCA)[ \t\xA0]*(?:Agreement|Contract)?[ \t\xA0]*(?:ID|Ref|No\.?|Number|#)?[ \t\xA0]*[:#-][ \t\xA0]*(?!Agreement\b)([A-Za-z0-9-]{4,25})\b/gi },
|
|
1600
1701
|
{ type: 'FINANCIAL', regex: /(?<=(?:^|[\r\n\t.;])[ \t\xA0]*(?:Daily|Weekly)(?:[ \t\xA0]+(?:ACH|Remittance|Debit|Payment|Transfer|Split(?:[ \t\xA0]+Funding)?|Holdback))+[ \t\xA0]*[:=][ \t\xA0]*)((?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’]+)/gi },
|
|
1601
|
-
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:
|
|
1702
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\s*|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])\s*)(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?(?:\s*(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))?\b|\b(?:\d[0-9,.'’\u2018\u2019]*\d|\d)[KMB]?\s*(?:\b(?:EUR|GBP|CHF|ILS|RUB|CAD|AUD|JPY|CNY|INR|BRL)\b|(?:R\$|[A-Z]{1,2}\$|[€£¥₪₽₹])))/gi },
|
|
1703
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\$\s*)?[0-9,.'’\u2018\u2019]*\d[KMB]?\s*\bUSD\b|\bUSD\s*\$?[0-9,.'’\u2018\u2019]*\d[KMB]?\b)/gi },
|
|
1704
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:(?:ending|opening|current|available|ledger|account)\s+)?(?:balance|wire|settlement|distribution|withdrawal|payout|remittance)\s*(?:was|is|of|[:=])\s*)[$€£¥₪₽₹]\s*[0-9,.'’\u2018\u2019]*\d[KMB]?\b/gi },
|
|
1602
1705
|
{ type: 'NAME', isContextName: true, isCorporateName: true, regex: /(?:MCA\s+Funder|Funder|ISO\s+Broker|Funding\s+Partner)[ \t\xA0]*[:#][ \t\xA0]*([A-Za-z0-9&.,\s'-]{2,40}?)(?=\r?\n|$|\s{3,}|\t|Rate|Factor|Advance|Amount|Terms)/gi }
|
|
1603
1706
|
]
|
|
1604
1707
|
};
|
|
1605
1708
|
|
|
1606
1709
|
let NAME_STOP_LIST = new Set([
|
|
1607
1710
|
'clinical note', 'case note', 'prod log', 'siem alert', 'critical security incident', 'security incident', 'hr review', 'crm export', 'bank statement', 'file export', 'database row', 'lease application', 'strategy export', 'action log', 'glossary query', 'tool comparison', 'call transcript', 'zendesk ticket', 'board minutes', 'agent context', 'config dump', 'database dump', 'patient note', 'medical record', 'admission note', 'discharge summary', 'progress note', 'hiring review', 'security audit', 'incident response', 'server log', 'system log', 'api response', 'error log', 'audit log', 'debug log',
|
|
1608
|
-
'due diligence', 'cap table', 'cap table ledger', 'series a', 'm&a', 'm&a due diligence',
|
|
1711
|
+
'due diligence', 'cap table', 'cap table ledger', 'series a', 'm&a', 'm&a due diligence', 'trunk group', 'route group', 'trunk group name', 'sip trunk',
|
|
1609
1712
|
'executive compensation', 'global mobility', 'equity grant', 'stock options', 'restricted stock units', 'vesting schedule', 'severance agreement', 'release of claims', 'retention bonus', 'sign-on bonus', 'labor condition application', 'permanent labor certification', 'alien registration number', 'certificate of sponsorship', 'whistleblower report', 'ethics hotline', 'change in control', 'golden parachute', 'deferred compensation', 'compa-ratio', 'turnover rate', 'attrition rate', 'time to hire', 'offer acceptance rate', 'human capital', 'people partner', 'compensation committee',
|
|
1610
1713
|
'bill of lading', 'sea waybill', 'air waybill', 'ocean bill of lading', 'ocean bill', 'shipping instruction', 'booking confirmation', 'booking reference', 'customs declaration', 'entry summary', 'single administrative document', 'cbp entry', 'cbp 7501', 'ata carnet', 'internal transaction', 'movement reference', 'vessel manifest', 'cargo manifest', 'verified gross', 'gross mass', 'container seal', 'bolt seal', 'bonded warehouse', 'free trade zone', 'per diem', 'lumper fee', 'chassis fee', 'terminal handling', 'bunker adjustment', 'freight forwarder', 'customs broker', 'customs agent', 'port agent', 'notify party', 'importer of record', 'exporter of record', 'incoterms 2020', 'hague-visby', 'hague visby', 'hamburg rules', 'rotterdam rules', 'montreal convention', 'warsaw convention', 'cmr convention', 'solas vgm', 'tariff schedule', 'duty rate', 'harbor maintenance fee', 'merchandise processing fee',
|
|
1611
1714
|
'funded debt', 'operating procedures', 'standard operating', 'equal credit', 'credit opportunity', 'statutory standards', 'financial covenant', 'covenant compliance',
|
|
@@ -1705,7 +1808,8 @@ let NAME_STOP_LIST = new Set([
|
|
|
1705
1808
|
'regular', 'hours', 'holiday', 'overtime', 'commission', 'bonus', 'bonuses', 'records', 'record', 'statement', 'statements', 'rate', 'rates', 'current', 'ytd', 'benefits', 'taxable', 'pre-tax', 'post-tax', 'reimbursements', 'reimbursement', 'fica', 'oasdi', 'disability', 'unemployment', 'sui', 'sdi', 'std', 'ltd', 'exemptions', 'exemption', 'allowances', 'allowance', 'filing', 'status', 'single', 'married', 'head', 'household', 'advice', 'frequency', 'bi-weekly', 'biweekly', 'weekly', 'monthly', 'semi-monthly', 'direct', 'deposit', 'routing', 'box', 'boxes', 'code', 'control', 'omb', 'copy', 'instructions', 'information', 'deferred', 'adoption', 'statutory', 'third-party', 'sick', 'form', 'schedule', 'w-2', 'w2', 'w-4', 'w4', '1099', 'k-1', '1040', 'fed', 'med', 'fwt', 'swt', 'fed w/h', 'fed med', 'locality', 'state wages', 'state tax', 'local wages', 'local tax', 'allocated', 'nonqualified', 'suff', 'suffix', 'allocated tips', 'advance eic', 'advance eic payment', 'dependent care', 'dependent care benefits', 'nonqualified plans', 'statutory employee', 'retirement plan', 'third-party sick pay',
|
|
1706
1809
|
'uk', 'eu', 'us', 'usa', 'dpa', 'ico', 'dpo', 'ciso', 'ssrn', 'elsevier', 'gdpr', 'ccpa', 'cpra', 'hipaa', 'soc2', 'iso27001', 'governance', 'regulatory', 'framework', 'mandate', 'mandates', 'guidance', 'statute', 'statutes', 'jurisdiction', 'jurisdictions', 'recital', 'article', 'articles', 'treatise', 'workstation', 'device', 'endpoint', 'blueprint', 'personal', 'cross-border', 'cross', 'border', 'transfer', 'retrieval', 'augmented', 'generation', 'limitation', 'discrimination', 'imposes', 'heavy', 'identifiable', 'bypasses', 'author', 'authors', 'contact', 'contacts', 'keywords', 'keyword', 'keys', 'key', 'separation', 'pre-print', 'preprint', 'abstract', 'structured', 'background', 'methods', 'results', 'discussion', 'conclusion', 'conclusions', 'introduction', 'overview', 'workflow', 'paradigm', 'nomenclature', 'repository', 'classification', 'phenotypes', 'biomedical', 'bioinformatics', 'identifiers', 'de-identification', 'sanitization', 'ephemeral', 'validation', 'validating', 'genomic', 'genomics', 'clinical', 'phenotype', 'target', 'corresponding', 'subject', 'biorxiv', 'medrxiv', 'arxiv', 'privacyscrubber', 'research', 'lead', 'architect', 'chief', 'founder', 'symbols', 'gene', 'genes', 'sample', 'barcode', 'pipeline', 'downstream', 'pedigree', 'trees', 'exposes', 'violates', 'protecting', 'anonymization', 'redacted', 'redaction', 'zero-trust', 'ztds',
|
|
1707
1810
|
'conventional', 'model', 'models', 'potential', 'multi', 'million', 'dollar', 'dollars', 'surrogate', 'surrogates', 'geographic', 'subdivisions', 'subdivision', 'inference', 'response', 'responses', 'latency', 'benchmarks', 'benchmark', 'experimental', 'methodology', 'informatics', 'ethics', 'accountability', 'civil', 'rights', 'perimeter', 'network', 'requirements', 'requirement', 'statutory', 'categories', 'category', 'regulations', 'regulation', 'penalties', 'penalty', 'disclosure', 'disclosures', 'clinician', 'terminal', 'transport', 'inpatient', 'discharge', 'summaries', 'operative', 'reports', 'outpatient', 'psychiatric', 'telehealth', 'consultation', 'pathology', 'sequencing', 'laboratory', 'sensitivity', 'specificity', 'proxy', 'gateways', 'gateway', 'packet', 'packets', 'inspection', 'declarations', 'availability', 'competing', 'interests', 'interventions', 'multicenter', 'multi-center', 'institution', 'institutional', 'protocol', 'deviations', 'adverse', 'events', 'abbreviations', 'agents', 'agent', 'committee', 'committees', 'board', 'boards', 'nih', 'pubmed', 'central', 'open', 'access', 'policy', 'trial', 'trials', 'crf', 'crfs', 'ehr', 'ehrs', 'baa', 'baas', 'hitech', 'safe', 'harbor', 'section',
|
|
1708
|
-
'general liability', 'commercial property', 'workers compensation', 'excess casualty', 'inland marine', 'ocean marine', 'commercial auto', 'first notice of loss', 'first notice', 'incident report', 'incurred losses', 'case reserve', 'loss run', 'loss history', 'subrogation claim', 'salvage recovery', 'treaty cession', 'reinsurance treaty', 'retention limit', 'public adjuster', 'independent adjuster', 'lead underwriter', 'producing agent', 'additional insured', 'named insured', 'injured worker', 'tpa examiner'
|
|
1811
|
+
'general liability', 'commercial property', 'workers compensation', 'excess casualty', 'inland marine', 'ocean marine', 'commercial auto', 'first notice of loss', 'first notice', 'incident report', 'incurred losses', 'case reserve', 'loss run', 'loss history', 'subrogation claim', 'salvage recovery', 'treaty cession', 'reinsurance treaty', 'retention limit', 'public adjuster', 'independent adjuster', 'lead underwriter', 'producing agent', 'additional insured', 'named insured', 'injured worker', 'tpa examiner',
|
|
1812
|
+
'são paulo', 'sao paulo', 'rio de janeiro', 'belo horizonte', 'brasília', 'brasilia', 'curitiba', 'porto alegre', 'salvador', 'fortaleza', 'recife', 'campinas', 'goiânia', 'goiania', 'manaus', 'belém', 'belem', 'florianópolis', 'florianopolis', 'vitória', 'vitoria', 'natal', 'maceió', 'maceio', 'joão pessoa', 'joao pessoa', 'prontuário médico', 'prontuario medico', 'evolução clínica', 'evolucao clinica', 'alta hospitalar', 'exame oftalmológico', 'exame oftalmologico', 'acuidade visual', 'pressão intraocular', 'pressao intraocular', 'fundo de olho', 'biomicroscopia', 'receita médica', 'receita medica', 'laudo médico', 'laudo medico', 'termo de consentimento']);
|
|
1709
1813
|
|
|
1710
1814
|
let JARGON_WORDS = new Set(['step', 'page', 'grade', 'version', 'course', 'class', 'follow', 'chapter', 'lesson', 'unit', 'marketing', 'manager', 'specialist', 'science', 'administration', 'university', 'skills', 'leadership', 'communication', 'working', 'proficiency', 'decision', 'driven', 'experience', 'summary', 'bachelor', 'ads', 'solutions', 'positioning', 'acquisition', 'strategy', 'research', 'database', 'forecast', 'interest', 'prepared', 'merchant', 'document', 'feedback', 'template', 'campaign', 'partners', 'settings', 'keystone', 'llm', 'gpt', 'chatgpt', 'openai', 'anthropic', 'claude', 'gemini', 'api', 'json', 'xml', 'html', 'css', 'javascript', 'python', 'golang', 'typescript', 'rust', 'fastapi', 'snowflake', 'kubernetes', 'terraform', 'docker', 'redis', 'kafka', 'pytorch', 'policy', 'terms', 'conditions', 'release', 'sprint', 'deployment', 'cluster', 'instance', 'package', 'module', 'revenue', 'margin', 'gross', 'quarter', 'system', 'code', 'data', 'cloud', 'server', 'database', 'artificial', 'intelligence', 'learning', 'generative', 'regular', 'hours', 'holiday', 'earnings', 'deductions', 'withheld', 'withholding', 'taxes', 'medicare', 'benefits', 'reimbursements', 'compensation', 'wages', 'code', 'uk', 'eu', 'us', 'usa', 'dpa', 'ico', 'dpo', 'ciso', 'ssrn', 'elsevier', 'gdpr', 'ccpa', 'cpra', 'hipaa', 'soc2', 'iso27001', 'governance', 'regulatory', 'framework', 'mandate', 'mandates', 'guidance', 'statute', 'statutes', 'jurisdiction', 'jurisdictions', 'recital', 'article', 'articles', 'treatise', 'workstation', 'device', 'endpoint', 'blueprint', 'personal', 'cross-border', 'cross', 'border', 'transfer', 'retrieval', 'augmented', 'generation', 'limitation', 'discrimination', 'imposes', 'heavy', 'identifiable', 'bypasses', 'author', 'authors', 'contact', 'contacts', 'keywords', 'keyword', 'keys', 'key', 'separation', 'pre-print', 'preprint', 'abstract', 'structured', 'background', 'methods', 'results', 'discussion', 'conclusion', 'conclusions', 'introduction', 'overview', 'workflow', 'paradigm', 'nomenclature', 'repository', 'classification', 'phenotypes', 'biomedical', 'bioinformatics', 'identifiers', 'de-identification', 'sanitization', 'ephemeral', 'validation', 'validating', 'genomic', 'genomics', 'clinical', 'phenotype', 'target', 'corresponding', 'subject', 'biorxiv', 'medrxiv', 'arxiv', 'privacyscrubber', 'research', 'lead', 'architect', 'chief', 'founder', 'symbols', 'gene', 'genes', 'sample', 'barcode', 'pipeline', 'downstream', 'pedigree', 'trees', 'exposes', 'violates', 'protecting', 'anonymization', 'redacted', 'redaction', 'zero-trust', 'ztds',
|
|
1711
1815
|
'conventional', 'model', 'models', 'potential', 'multi', 'million', 'dollar', 'dollars', 'surrogate', 'surrogates', 'geographic', 'subdivisions', 'subdivision', 'inference', 'response', 'responses', 'latency', 'benchmarks', 'benchmark', 'experimental', 'methodology', 'informatics', 'ethics', 'accountability', 'civil', 'rights', 'perimeter', 'network', 'requirements', 'requirement', 'statutory', 'categories', 'category', 'regulations', 'regulation', 'penalties', 'penalty', 'disclosure', 'disclosures', 'clinician', 'terminal', 'transport', 'inpatient', 'discharge', 'summaries', 'operative', 'reports', 'outpatient', 'psychiatric', 'telehealth', 'consultation', 'pathology', 'sequencing', 'laboratory', 'sensitivity', 'specificity', 'proxy', 'gateways', 'gateway', 'packet', 'packets', 'inspection', 'declarations', 'availability', 'competing', 'interests', 'interventions', 'multicenter', 'multi-center', 'institution', 'institutional', 'protocol', 'deviations', 'adverse', 'events', 'abbreviations', 'agents', 'agent', 'committee', 'committees', 'board', 'boards', 'nih', 'pubmed', 'central', 'open', 'access', 'policy', 'trial', 'trials', 'crf', 'crfs', 'ehr', 'ehrs', 'baa', 'baas', 'hitech', 'safe', 'harbor', 'section',
|
|
@@ -1717,7 +1821,7 @@ const US_STATES_SET = new Set([
|
|
|
1717
1821
|
]);
|
|
1718
1822
|
|
|
1719
1823
|
const CORPORATE_SUFFIXES = new Set([
|
|
1720
|
-
'inc', 'llc', 'corp', 'corporation', 'ltd', 'limited', 'co', 'company',
|
|
1824
|
+
'inc', 'llc', 'corp', 'corporation', 'ltd', 'limited', 'co', 'company', 'ltda', 'eireli', 'sa', 's/a',
|
|
1721
1825
|
'group', 'holdings', 'solutions', 'services', 'servicing', 'technologies', 'logistics',
|
|
1722
1826
|
'industries', 'capital', 'bank', 'partners', 'llp', 'pllc', 'usa',
|
|
1723
1827
|
'gmbh', 'ag', 'ohg', 'kg', 'ug', 'ev', 'sp', 'zoo', 'oo', 'automotive',
|
|
@@ -1746,7 +1850,7 @@ let NOT_NAME_WORDS = new Set([
|
|
|
1746
1850
|
'substation', 'feeder', 'transformer', 'recloser', 'inverter', 'turbine', 'synchrophasor', 'scada', 'ics', 'dcs', 'plc', 'rtu', 'ied', 'pmu', 'ami', 'bess', 'derms', 'adms', 'hvdc', 'facts', 'avr', 'agc', 'lmp', 'ppa', 'nerc cip', 'cip-002', 'cip-014', 'ferc', 'pjm', 'miso', 'caiso', 'ercot', 'nyiso', 'iso-ne', 'spp', 'entso-e', 'wecc', 'serc', 'rfc', 'tre', 'mro', 'npcc', 'dnp3', 'modbus', 'opc ua', 'openadr', 'active power', 'reactive power', 'apparent power', 'power factor', 'peak demand', 'curtailment', 'bulk electric system', 'critical infrastructure', 'smart grid', 'smart meter',
|
|
1747
1851
|
'utility', 'utilities', 'electric', 'electrical', 'meter', 'metering', 'service point', 'delivery point', 'premise', 'premises', 'programmable', 'logic', 'telemetry', 'solar', 'plant', 'wind', 'storage', 'battery', 'bulk', 'ua', 'mqtt', 'sparkplug',
|
|
1748
1852
|
'vehicle', 'primary', 'secondary', 'asset', 'fleet', 'engine', 'controller', 'dealer', 'freeze', 'frame', 'work order', 'repair order', 'sedan', 'suv', 'iso 26262', 'iso 21434', 'sae j1939', 'sae j1772', 'sae j1979', 'iso 15118', 'iso 14229', 'ocpp', 'can bus', 'can fd', 'flexray', 'some/ip', 'doip', 'diagnostic trouble codes', 'diagnostic', 'trouble', 'codes', 'dtc', 'obd', 'obd-ii', 'ecu', 'bcm', 'tcu', 'pcm', 'vcu', 'bms', 'telematics', 'odometer', 'powertrain', 'inverter', 'alternator', 'transponder', 'evse', 'dcfc', 'ccs1', 'ccs2', 'nacs', 'chademo', 'state of charge', 'state of health', 'soc', 'soh', 'adas', 'lidar', 'radar', 'asil', 'asil-d', 'nhtsa', 'fmvss', 'fmcsa', 'wltp', 'carb', 'p0300', 'p0420', 'u0100', 'b0001', 'c0035',
|
|
1749
|
-
'sec', 'cftc', 'finra', 'fdic', 'occ', 'cfpb', 'fedwire', 'reserve', 'federal', 'law', 'corporation', 'delaware', 'dgcl',
|
|
1853
|
+
'sec', 'cftc', 'finra', 'fdic', 'occ', 'cfpb', 'fedwire', 'reserve', 'federal', 'law', 'corporation', 'delaware', 'dgcl', 'group', 'holdings', 'limited', 'inc', 'llc', 'corp', 'co',
|
|
1750
1854
|
'lms', 'edtech', 'canvas', 'blackboard', 'moodle', 'schoology', 'brightspace', 'proctorio', 'honorlock', 'respondus', 'proctoru', 'coppa', 'idea', 'section 504', 'clery', 'clery act', 'title iv', 'sai', 'student aid index', 'student aid report', 'bip', 'lep', 'ell', 'esl', 'sevis', 'form i-20', 'ds-2019', 'sat', 'act', 'gre', 'gmat', 'mcat', 'lsat', 'toefl', 'ielts', 'abet', 'wasc', 'sacscoc', 'hlc', 'neche', 'valedictorian', 'salutatorian', 'cum laude', 'magna cum laude', 'summa cum laude', 'ed.d', 'edd', 'j.d.', 'student', 'learner', 'conduct', 'behavioral', 'intervention', 'english', 'proficiency', 'accommodations', 'accommodation', 'proctoring',
|
|
1751
1855
|
'3gpp', 'etsi', 'itu-t', 'ietf', 'rfc', 'sip', 'sdp', 'rtp', 'rtcp', 'srtp', 'stun', 'turn', 'ice', 'webrtc', 'ss7', 'sigtran', 'diameter', 'radius', 'docsis', 'gpon', 'xgs-pon', 'dwdm', 'cwdm', 'otn', 'mpls', 'bgp', 'ospf', 'is-is', 'ebgp', 'ibgp', 'qos', 'diffserv', 'volte', 'vonr', 'vowifi', 'esim', 'imsi', 'imei', 'imeisv', 'iccid', 'msisdn', 'enodeb', 'gnodeb', 'nodeb', 'cell id', 'pci', 'tac', 'lac', 'cgi', 'ecgi', 'tr-069', 'tr-369', 'cwmp', 'g.711', 'g.729', 'g.722', 'opus', 'amr-wb', 'evs', 'mos', 'jitter', 'packet loss', 'rtt', 'bitrate', 'c-band', 'mmwave', 'sub-6', 'telecom', 'carrier', 'backhaul', 'fronthaul', 'peering', 'circuit id', 'facility id',
|
|
1752
1856
|
'caller', 'evaluator', 'diarization', 'transcript', 'transcription', 'scorecard', 'ivr', 'dtmf', 'ani', 'cli', 'dnis', 'aht', 'asa', 'fcr', 'csat', 'nps', 'wrap-up', 'wrapup', 'genesys', 'five9', 'nice', 'incontact', 'talkdesk', 'ucid', 'telephony',
|
|
@@ -2310,15 +2414,15 @@ const PROFILE_JARGON = {
|
|
|
2310
2414
|
const PROFILE_ALIAS_MAP = {
|
|
2311
2415
|
'general': 'general',
|
|
2312
2416
|
'underwriting': 'underwriting', 'lending': 'underwriting', 'mortgage': 'underwriting', 'loan': 'underwriting', 'income': 'underwriting', 'income_verification': 'underwriting', 'payroll': 'underwriting', 'w2': 'underwriting', 'paystub': 'underwriting',
|
|
2313
|
-
'medical': 'medical', 'healthcare': 'medical', 'health': 'medical', 'pharma': 'pharma', 'clinical': 'pharma', 'trials': 'pharma', 'lifesciences': 'pharma', 'cro': 'pharma', 'pharmacovigilance': 'pharma', 'hipaa': 'medical',
|
|
2417
|
+
'medical': 'medical', 'healthcare': 'medical', 'health': 'medical', 'doctor': 'medical', 'physician': 'medical', 'clinic': 'medical', 'hospital': 'medical', 'pharma': 'pharma', 'clinical': 'pharma', 'trials': 'pharma', 'lifesciences': 'pharma', 'cro': 'pharma', 'pharmacovigilance': 'pharma', 'hipaa': 'medical',
|
|
2314
2418
|
'biotech': 'biotech', 'genomics': 'biotech', 'bioinformatics': 'biotech', 'genetics': 'biotech', 'sequencing': 'biotech', 'dna': 'biotech',
|
|
2315
|
-
'
|
|
2419
|
+
'finance': 'finance', 'financial': 'finance', 'fintech': 'finance', 'banking': 'finance', 'bank': 'finance', 'payments': 'finance', 'bizops': 'bizops', 'logistics': 'bizops', 'supplychain': 'bizops', 'customs': 'bizops', 'freight': 'bizops', 'shipping': 'bizops', 'trade': 'bizops', 'ops': 'bizops', 'erp': 'bizops', 'sales': 'sales', 'procurement': 'sales', 'clm': 'sales', 'contracts': 'sales', 'sourcing': 'sales', 'wealthmgmt': 'wealthmgmt', 'wealth': 'wealthmgmt', 'insurance': 'insurance', 'accounting': 'accounting', 'tax': 'accounting', 'taxes': 'accounting', 'invoicing': 'accounting', 'invoice': 'accounting', 'ap': 'accounting', 'ar': 'accounting', 'ledger': 'accounting', 'pci': 'finance',
|
|
2420
|
+
'legal': 'legal', 'law': 'legal', 'attorney': 'legal', 'litigation': 'legal', 'compliance': 'compliance', 'defense': 'compliance', 'gov': 'compliance', 'government': 'compliance', 'dod': 'compliance', 'cmmc': 'compliance', 'cui': 'compliance', 'itar': 'compliance', 'ccpa': 'ccpa', 'gdpr': 'compliance', 'soc2': 'compliance', 'iso27001': 'compliance', 'nist': 'compliance', 'dpo': 'compliance', 'grc': 'compliance',
|
|
2421
|
+
'engineering': 'engineering', 'dev': 'dev', 'code': 'dev', 'software': 'dev', 'developer': 'dev', 'api': 'dev', 'devops': 'engineering', 'tech': 'tech', 'network': 'tech', 'manufacturing': 'engineering', 'industrial': 'engineering', 'production': 'engineering', 'factory': 'engineering', 'plant': 'engineering',
|
|
2316
2422
|
'telecom': 'telecom', 'callcenter': 'telecom', 'contactcenter': 'telecom', 'voip': 'telecom', 'telephony': 'telecom', 'ivr': 'telecom', 'telco': 'telecom', 'sip': 'telecom', 'cdr': 'telecom', 'audio': 'telecom',
|
|
2317
|
-
'
|
|
2318
|
-
'
|
|
2319
|
-
'hr': 'hr', 'people': 'hr', 'talent': 'hr', 'mobility': 'hr', 'recruiting': 'hr', 'hcm': 'hr', 'compensation': 'hr', 'security': 'security', 'marketing': 'marketing', 'support': 'support',
|
|
2423
|
+
'agents': 'agents', 'ai_agents': 'agents', 'agent': 'agents', 'langchain': 'agents', 'llamaindex': 'agents', 'mcp': 'agents', 'vector': 'agents', 'rag': 'agents',
|
|
2424
|
+
'hr': 'hr', 'people': 'hr', 'talent': 'hr', 'mobility': 'hr', 'recruiting': 'hr', 'hcm': 'hr', 'compensation': 'hr', 'security': 'security', 'cybersec': 'security', 'cybersecurity': 'security', 'infosec': 'security', 'secops': 'security', 'marketing': 'marketing', 'support': 'support',
|
|
2320
2425
|
'realestate': 'realestate', 'realty': 'realestate', 'property': 'realestate', 'title': 'realestate', 'escrow': 'realestate', 'hoa': 'realestate', 'academic': 'academic', 'education': 'academic', 'edu': 'academic', 'student': 'academic', 'highered': 'academic', 'edtech': 'academic', 'lms': 'academic',
|
|
2321
|
-
'agents': 'agents', 'ai_agents': 'agents', 'agent': 'agents', 'langchain': 'agents', 'llamaindex': 'agents', 'mcp': 'agents', 'vector': 'agents',
|
|
2322
2426
|
'creative': 'creative',
|
|
2323
2427
|
'personal': 'personal', 'vip': 'personal', 'executive': 'personal', 'protection': 'personal', 'familyoffice': 'personal', 'family_office': 'personal',
|
|
2324
2428
|
'automotive': 'automotive', 'auto': 'automotive', 'vehicle': 'automotive', 'telematics': 'automotive', 'ev': 'automotive', 'fleet': 'automotive',
|
|
@@ -2363,7 +2467,7 @@ const PROFILE_JARGON = {
|
|
|
2363
2467
|
// Israel Teudat Zehut & Corporate ID (H.P. / 50-58 prefixes): 8 or 9 digits, Luhn check (Mod 10)
|
|
2364
2468
|
if (digits.length < 8 || digits.length > 9) return false;
|
|
2365
2469
|
const prefix = fullText.substring(Math.max(0, start - 40), start);
|
|
2366
|
-
const hasContext = /(?:תעודת\s
|
|
2470
|
+
const hasContext = /(?:תעודת\s+זהות|ת\.?ז\.?|ת["״]ז|מספר\s+זהות|מ\.?ז\.?|Teudat\s+Zehut|TZ|תעודה|ח\.?פ\.?|ח["״]פ|ע\.?ר\.?|ע\.?מ\.?|ע["״]מ|מע["״]מ|מספר\s+תאגיד|חברה\s+פרטית|עוסק\s+מורשה|חברה)/i.test(prefix);
|
|
2367
2471
|
const idStr = digits.padStart(9, '0');
|
|
2368
2472
|
let sum = 0;
|
|
2369
2473
|
for (let i = 0; i < 9; i++) {
|
|
@@ -2396,6 +2500,10 @@ const PROFILE_JARGON = {
|
|
|
2396
2500
|
// UK NHS Number: 10 digits, Mod 11 check
|
|
2397
2501
|
if (digits.length !== 10) return false;
|
|
2398
2502
|
const hasContext = /NHS/i.test(prefix);
|
|
2503
|
+
if (!hasContext) {
|
|
2504
|
+
if (/^\d{3}-\d{3}-\d{4}$/.test(val.trim())) return false;
|
|
2505
|
+
if (/(?:phone|tel|call|mobile|cell|fax|contact|sms|whatsapp|נייד|טלפון)/i.test(prefix)) return false;
|
|
2506
|
+
}
|
|
2399
2507
|
const weights = [10, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
2400
2508
|
let sum = 0;
|
|
2401
2509
|
for (let i = 0; i < 9; i++) sum += Number(digits[i]) * weights[i];
|
|
@@ -2567,13 +2675,229 @@ const PROFILE_JARGON = {
|
|
|
2567
2675
|
return hasContext ? (valid || true) : valid;
|
|
2568
2676
|
}
|
|
2569
2677
|
|
|
2678
|
+
case 'mod11_br_cpf': {
|
|
2679
|
+
const clean = val.replace(/\D/g, '');
|
|
2680
|
+
if (clean.length !== 11 || /^(\d)\1{10}$/.test(clean)) return false;
|
|
2681
|
+
const prefix = fullText.substring(Math.max(0, start - 35), start);
|
|
2682
|
+
const hasContext = /\b(?:CPF|Cadastro\s+de\s+Pessoas?\s+F[íi]sicas?)\b/i.test(prefix);
|
|
2683
|
+
const isPunctuated = /^\d{3}\.\d{3}\.\d{3}-\d{2}$/.test(val.trim());
|
|
2684
|
+
let s1 = 0, s2 = 0;
|
|
2685
|
+
for (let i = 0; i < 9; i++) {
|
|
2686
|
+
const d = clean.charCodeAt(i) - 48;
|
|
2687
|
+
s1 += d * (10 - i);
|
|
2688
|
+
s2 += d * (11 - i);
|
|
2689
|
+
}
|
|
2690
|
+
const d1 = (s1 * 10) % 11 === 10 ? 0 : (s1 * 10) % 11;
|
|
2691
|
+
s2 += d1 * 2;
|
|
2692
|
+
const d2 = (s2 * 10) % 11 === 10 ? 0 : (s2 * 10) % 11;
|
|
2693
|
+
const valid = (d1 === (clean.charCodeAt(9) - 48) && d2 === (clean.charCodeAt(10) - 48));
|
|
2694
|
+
return (hasContext || isPunctuated) ? true : valid;
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
case 'mod11_br_cnpj': {
|
|
2698
|
+
const clean = val.replace(/\D/g, '');
|
|
2699
|
+
if (clean.length !== 14 || /^(\d)\1{13}$/.test(clean)) return false;
|
|
2700
|
+
const prefix = fullText.substring(Math.max(0, start - 35), start);
|
|
2701
|
+
const hasContext = /\b(?:CNPJ|Cadastro\s+Nacional\s+da\s+Pessoa\s+Jur[íi]dica)\b/i.test(prefix);
|
|
2702
|
+
const isPunctuated = /^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}$/.test(val.trim());
|
|
2703
|
+
const w1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
2704
|
+
const w2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
2705
|
+
let s1 = 0, s2 = 0;
|
|
2706
|
+
for (let i = 0; i < 12; i++) {
|
|
2707
|
+
const d = clean.charCodeAt(i) - 48;
|
|
2708
|
+
s1 += d * w1[i];
|
|
2709
|
+
s2 += d * w2[i];
|
|
2710
|
+
}
|
|
2711
|
+
const r1 = s1 % 11;
|
|
2712
|
+
const d1 = r1 < 2 ? 0 : 11 - r1;
|
|
2713
|
+
s2 += d1 * w2[12];
|
|
2714
|
+
const r2 = s2 % 11;
|
|
2715
|
+
const d2 = r2 < 2 ? 0 : 11 - r2;
|
|
2716
|
+
const valid = (d1 === (clean.charCodeAt(12) - 48) && d2 === (clean.charCodeAt(13) - 48));
|
|
2717
|
+
return (hasContext || isPunctuated) ? true : valid;
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
case 'aadhaar_in': {
|
|
2721
|
+
const clean = val.replace(/\D/g, '');
|
|
2722
|
+
if (clean.length !== 12 || /^[01]/.test(clean) || /^(\d)\1{11}$/.test(clean)) return false;
|
|
2723
|
+
return true;
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
case 'mod10_pl_pesel': {
|
|
2727
|
+
const clean = val.replace(/\D/g, '');
|
|
2728
|
+
if (clean.length !== 11 || /^(\d)\1{10}$/.test(clean)) return false;
|
|
2729
|
+
const prefix = fullText.substring(Math.max(0, start - 30), start);
|
|
2730
|
+
const hasContext = /\bPESEL\b/i.test(prefix);
|
|
2731
|
+
const weights = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
|
|
2732
|
+
let sum = 0;
|
|
2733
|
+
for (let i = 0; i < 10; i++) sum += (clean.charCodeAt(i) - 48) * weights[i];
|
|
2734
|
+
const check = (10 - (sum % 10)) % 10;
|
|
2735
|
+
const valid = (check === (clean.charCodeAt(10) - 48));
|
|
2736
|
+
return hasContext ? true : valid;
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
case 'mod11_pl_nip': {
|
|
2740
|
+
const clean = val.replace(/\D/g, '');
|
|
2741
|
+
if (clean.length !== 10 || /^(\d)\1{9}$/.test(clean)) return false;
|
|
2742
|
+
const prefix = fullText.substring(Math.max(0, start - 30), start);
|
|
2743
|
+
const hasContext = /\bNIP\b/i.test(prefix);
|
|
2744
|
+
const weights = [6, 5, 7, 2, 3, 4, 5, 6, 7];
|
|
2745
|
+
let sum = 0;
|
|
2746
|
+
for (let i = 0; i < 9; i++) sum += (clean.charCodeAt(i) - 48) * weights[i];
|
|
2747
|
+
const check = sum % 11;
|
|
2748
|
+
if (check === 10 && !hasContext) return false;
|
|
2749
|
+
const valid = (check === (clean.charCodeAt(9) - 48));
|
|
2750
|
+
return hasContext ? true : valid;
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
case 'mod11_ar_cuit': {
|
|
2754
|
+
const clean = val.replace(/\D/g, '');
|
|
2755
|
+
if (clean.length !== 11) return false;
|
|
2756
|
+
const prefix = fullText.substring(Math.max(0, start - 30), start);
|
|
2757
|
+
const hasContext = /\bCUI[TL]\b/i.test(prefix);
|
|
2758
|
+
const isPunctuated = /^(?:20|23|24|27|30|33|34)-\d{8}-\d$/.test(val.trim());
|
|
2759
|
+
const weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
|
|
2760
|
+
let sum = 0;
|
|
2761
|
+
for (let i = 0; i < 10; i++) sum += (clean.charCodeAt(i) - 48) * weights[i];
|
|
2762
|
+
let check = 11 - (sum % 11);
|
|
2763
|
+
if (check === 11) check = 0;
|
|
2764
|
+
else if (check === 10) check = 9;
|
|
2765
|
+
const valid = (check === (clean.charCodeAt(10) - 48));
|
|
2766
|
+
return (hasContext || isPunctuated) ? true : valid;
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
case 'luhn_se_personnummer': {
|
|
2770
|
+
let clean = val.replace(/\D/g, '');
|
|
2771
|
+
if (clean.length === 12) clean = clean.slice(2);
|
|
2772
|
+
if (clean.length !== 10 || /^(\d)\1{9}$/.test(clean)) return false;
|
|
2773
|
+
const prefix = fullText.substring(Math.max(0, start - 35), start);
|
|
2774
|
+
const hasContext = /\b(?:Personnummer|Samordningsnummer|Pnr)\b/i.test(prefix);
|
|
2775
|
+
let sum = 0;
|
|
2776
|
+
for (let i = 0; i < 10; i++) {
|
|
2777
|
+
let inc = (clean.charCodeAt(i) - 48) * ((i % 2 === 0) ? 2 : 1);
|
|
2778
|
+
if (inc > 9) inc -= 9;
|
|
2779
|
+
sum += inc;
|
|
2780
|
+
}
|
|
2781
|
+
const valid = (sum % 10 === 0);
|
|
2782
|
+
return hasContext ? true : valid;
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
case 'ean13_ch_ahv': {
|
|
2786
|
+
const clean = val.replace(/\D/g, '');
|
|
2787
|
+
if (clean.length !== 13 || !clean.startsWith('756')) return false;
|
|
2788
|
+
const prefix = fullText.substring(Math.max(0, start - 35), start);
|
|
2789
|
+
const hasContext = /\b(?:AHV|AVS|OASI)\b/i.test(prefix);
|
|
2790
|
+
const isPunctuated = /^756\.\d{4}\.\d{4}\.\d{2}$/.test(val.trim());
|
|
2791
|
+
let sum = 0;
|
|
2792
|
+
for (let i = 0; i < 12; i++) {
|
|
2793
|
+
sum += (clean.charCodeAt(i) - 48) * ((i % 2 === 0) ? 1 : 3);
|
|
2794
|
+
}
|
|
2795
|
+
const check = (10 - (sum % 10)) % 10;
|
|
2796
|
+
const valid = (check === (clean.charCodeAt(12) - 48));
|
|
2797
|
+
return (hasContext || isPunctuated) ? true : valid;
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
case 'mod11_2_cn_id': {
|
|
2801
|
+
const clean = val.replace(/\s+/g, '').toUpperCase();
|
|
2802
|
+
if (!/^\d{17}[0-9X]$/.test(clean)) return false;
|
|
2803
|
+
const hasContext = /\b(?:Shenfenzheng|CN\s+ID|Resident\s+ID)\b|身份证/iu.test(prefix);
|
|
2804
|
+
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
|
2805
|
+
const checkChars = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
|
2806
|
+
let sum = 0;
|
|
2807
|
+
for (let i = 0; i < 17; i++) {
|
|
2808
|
+
sum += (clean.charCodeAt(i) - 48) * weights[i];
|
|
2809
|
+
}
|
|
2810
|
+
const valid = (checkChars[sum % 11] === clean[17]);
|
|
2811
|
+
return hasContext ? true : valid;
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
case 'mod10_tw_id': {
|
|
2815
|
+
const clean = val.replace(/\s+/g, '').toUpperCase();
|
|
2816
|
+
if (!/^[A-Z][1289]\d{8}$/.test(clean)) return false;
|
|
2817
|
+
const hasContext = /\b(?:TW\s+ID|Taiwan\s+ID|ROC\s+ID)\b|身分證/iu.test(prefix);
|
|
2818
|
+
const letterMap = {
|
|
2819
|
+
A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, G: 16, H: 17, I: 34,
|
|
2820
|
+
J: 18, K: 19, L: 20, M: 21, N: 22, O: 35, P: 23, Q: 24, R: 25,
|
|
2821
|
+
S: 26, T: 27, U: 28, V: 29, W: 32, X: 30, Y: 31, Z: 33
|
|
2822
|
+
};
|
|
2823
|
+
const code = letterMap[clean[0]];
|
|
2824
|
+
if (!code) return false;
|
|
2825
|
+
const weights = [8, 7, 6, 5, 4, 3, 2, 1, 1];
|
|
2826
|
+
let sum = Math.floor(code / 10) + (code % 10) * 9;
|
|
2827
|
+
for (let i = 0; i < 9; i++) {
|
|
2828
|
+
sum += (clean.charCodeAt(i + 1) - 48) * weights[i];
|
|
2829
|
+
}
|
|
2830
|
+
const valid = (sum % 10 === 0);
|
|
2831
|
+
return hasContext ? true : valid;
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
case 'mod11_kr_rrn': {
|
|
2835
|
+
const clean = val.replace(/\D/g, '');
|
|
2836
|
+
if (clean.length !== 13) return false;
|
|
2837
|
+
const hasContext = /\b(?:RRN|Jumin)\b/i.test(prefix);
|
|
2838
|
+
const isHyphenated = /^\d{6}-\d{7}$/.test(val.trim());
|
|
2839
|
+
const weights = [2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5];
|
|
2840
|
+
let sum = 0;
|
|
2841
|
+
for (let i = 0; i < 12; i++) {
|
|
2842
|
+
sum += (clean.charCodeAt(i) - 48) * weights[i];
|
|
2843
|
+
}
|
|
2844
|
+
const check = (11 - (sum % 11)) % 10;
|
|
2845
|
+
const valid = (check === (clean.charCodeAt(12) - 48));
|
|
2846
|
+
return (hasContext || isHyphenated) ? true : valid;
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
case 'mod11_pt_nif': {
|
|
2850
|
+
const clean = val.replace(/\D/g, '');
|
|
2851
|
+
if (clean.length !== 9) return false;
|
|
2852
|
+
const hasContext = /\b(?:PT\s+NIF|NIF|NIPC|Contribuinte)\b/i.test(prefix);
|
|
2853
|
+
let sum = 0;
|
|
2854
|
+
for (let i = 0; i < 8; i++) {
|
|
2855
|
+
sum += (clean.charCodeAt(i) - 48) * (9 - i);
|
|
2856
|
+
}
|
|
2857
|
+
const rem = sum % 11;
|
|
2858
|
+
const check = rem < 2 ? 0 : 11 - rem;
|
|
2859
|
+
const valid = (check === (clean.charCodeAt(8) - 48));
|
|
2860
|
+
return hasContext ? true : valid;
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2570
2863
|
default:
|
|
2571
2864
|
return true;
|
|
2572
2865
|
}
|
|
2573
2866
|
}
|
|
2574
2867
|
|
|
2868
|
+
const HOMOGLYPH_EMAIL_MAP = {
|
|
2869
|
+
'\u0430': 'a', '\u0410': 'A', '\u0435': 'e', '\u0415': 'E',
|
|
2870
|
+
'\u043E': 'o', '\u041E': 'O', '\u0440': 'p', '\u0420': 'P',
|
|
2871
|
+
'\u0441': 'c', '\u0421': 'C', '\u0443': 'y', '\u0423': 'Y',
|
|
2872
|
+
'\u0445': 'x', '\u0425': 'X', '\u0456': 'i', '\u0406': 'I',
|
|
2873
|
+
'\u0458': 'j', '\u0408': 'J', '\u04CF': 'l', '\u04C0': 'I',
|
|
2874
|
+
'\u03B1': 'a', '\u03BF': 'o', '\u03C1': 'p', '\u03B5': 'e',
|
|
2875
|
+
'\u03BA': 'k', '\u03BD': 'v', '\u03C4': 't', '\u03C5': 'u'
|
|
2876
|
+
};
|
|
2877
|
+
|
|
2878
|
+
function normalizeEnclosedDigit(ch) {
|
|
2879
|
+
const code = ch.charCodeAt(0);
|
|
2880
|
+
if (code === 0x24EA || code === 0x24FF) return '0';
|
|
2881
|
+
if (code >= 0x2460 && code <= 0x2468) return String(code - 0x2460 + 1);
|
|
2882
|
+
if (code >= 0x2776 && code <= 0x277E) return String(code - 0x2776 + 1);
|
|
2883
|
+
if (code >= 0x2780 && code <= 0x2788) return String(code - 0x2780 + 1);
|
|
2884
|
+
if (code >= 0x278A && code <= 0x2792) return String(code - 0x278A + 1);
|
|
2885
|
+
return ch;
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2575
2888
|
function detectMatches(text, activeProfile = 'general', customRules = [], nlpNames = [], enabledEntities = null, mlEntities = []) {
|
|
2576
|
-
|
|
2889
|
+
const normalizedInput = typeof text === 'string' && typeof text.normalize === 'function' ? text.normalize('NFC') : String(text || '');
|
|
2890
|
+
let textToProcess = stitchOrphanedNameLines(normalizedInput, activeProfile)
|
|
2891
|
+
.replace(/[\u034f\u180e\u200b-\u200f\u202a-\u202e\u2060-\u2069\ufeff\u00ad]/gi, '')
|
|
2892
|
+
.replace(/[\uFF0B\uFF0D-\uFF1A\uFF20-\uFF3A\uFF3F\uFF41-\uFF5A]/g, ch => String.fromCharCode(ch.charCodeAt(0) - 0xFEE0))
|
|
2893
|
+
.replace(/[\u{1D400}-\u{1D7FF}]/gu, ch => ch.normalize('NFKD'))
|
|
2894
|
+
.replace(/[\u2460-\u2468\u24EA\u24FF\u2776-\u277E\u2780-\u2788\u278A-\u2792]/g, normalizeEnclosedDigit)
|
|
2895
|
+
.replace(/[^\s@<>,"']+@[^\s@<>,"']+\.[^\s@<>,"']+/g, token => {
|
|
2896
|
+
if (/[a-zA-Z0-9]/.test(token) && /[\u0400-\u04FF\u0370-\u03FF]/.test(token)) {
|
|
2897
|
+
return token.replace(/[\u0400-\u04FF\u0370-\u03FF]/g, ch => HOMOGLYPH_EMAIL_MAP[ch] || ch);
|
|
2898
|
+
}
|
|
2899
|
+
return token;
|
|
2900
|
+
});
|
|
2577
2901
|
textToProcess = textToProcess.replace(/([a-z])(Email|Phone|Mobile|Tel|Address|IP|ID|URL|SSN|Date):/g, '$1 $2:');
|
|
2578
2902
|
|
|
2579
2903
|
let matches = [];
|
|
@@ -2649,9 +2973,9 @@ const PROFILE_JARGON = {
|
|
|
2649
2973
|
matches.push({ start, end, value: matchedText, type: rule.type });
|
|
2650
2974
|
} else {
|
|
2651
2975
|
if (rule.type === 'NAME') {
|
|
2652
|
-
matchedText = matchedText.replace(/[
|
|
2976
|
+
matchedText = matchedText.replace(/[,;:\s]+$/, '').trim();
|
|
2653
2977
|
if (!/\b[A-Za-z]\.$/.test(matchedText) && !/\b(?:Jr|Sr)\.$/.test(matchedText)) {
|
|
2654
|
-
matchedText = matchedText.replace(
|
|
2978
|
+
matchedText = matchedText.replace(/[.\s]+$/, '').trim();
|
|
2655
2979
|
}
|
|
2656
2980
|
}
|
|
2657
2981
|
let val = matchedText.toLowerCase().trim();
|
|
@@ -2808,16 +3132,16 @@ const PROFILE_JARGON = {
|
|
|
2808
3132
|
}
|
|
2809
3133
|
|
|
2810
3134
|
const LABEL_ALIASES = {
|
|
2811
|
-
NAME: ['NAME', 'NAMES', 'USERNAME', 'USER_NAME', 'USER', 'USERS', 'CLIENTNAME', 'CLIENT_NAME', 'CANDIDATE_NAME', 'FULL_NAME', 'FIRSTNAME', 'FIRST_NAME', 'LASTNAME', 'LAST_NAME', 'SURNAME', 'ИМЯ', 'ИМЕНА', 'ПОЛЬЗОВАТЕЛЬ', 'ФИО', 'КЛИЕНТ', 'NOMBRE', 'NOMBRES', 'USUARIO', 'CLIENTE', 'NOM', 'NOMS', 'UTILISATEUR', '
|
|
2812
|
-
EMAIL: ['EMAIL', 'EMAILS', 'EMAILADDR', 'EMAIL_ADDR', 'EMAILADDRESS', 'EMAIL_ADDRESS', 'EMAIL_ADR', 'MAIL', 'MAILS', 'ПОЧТА', 'ЭЛ_ПОЧТА', 'АДРЕС_ПОЧТЫ', 'МЕЙЛ', 'МАЙЛ', 'CORREO', 'COURRIEL', 'CORREO_ELECTRONICO', 'MEL'],
|
|
2813
|
-
PHONE: ['PHONE', 'PHONES', 'PHONENUM', 'PHONE_NUM', 'PHONENUMBER', 'PHONE_NUMBER', 'TEL', 'TELS', 'TELEPHONE', 'TELEPHONES', 'MOBILE', 'CELL', 'ТЕЛЕФОН', 'ТЕЛЕФОНЫ', 'НОМЕР_ТЕЛЕФОНА', 'НОМЕР', 'MOVIL', 'PORTABLE', 'HANDY', 'TELEFONI', 'CELLULARE'],
|
|
2814
|
-
ID: ['ID', 'IDS', 'IDNUM', 'ID_NUM', 'IDNUMBER', 'ID_NUMBER', 'IDENTIFIER', 'IDENTIFIERS', 'ARN', 'ARNS', 'PASSPORT', 'SSN', 'EIN', 'TAXID', 'TAX_ID', 'LICENSE', 'LICENSE_PLATE', 'DEMOGRAPHIC', 'DEMOGRAPHICS', 'ИД', 'ИДЕНТИФИКАТОР', 'ПАСПОРТ', 'СНИЛС', 'ИНН', 'IDENTIFICADOR', 'PASAPORTE', 'IDENTIFIANT', 'PASSEPORT', 'IDENTIFIKATOR', 'PASS', 'IDENTIFICATORE', 'PASSAPORTO'],
|
|
2815
|
-
FINANCIAL: ['FINANCIAL', 'FINANCIALS', 'MONEY', 'AMOUNT', 'PRICE', 'COST', 'CARD', 'CREDITCARD', 'DEBITCARD', 'ACCOUNT', 'IBAN', 'BIC', 'ДЕНЬГИ', 'СУММА', 'КАРТА', 'СЧЕТ', 'БАНК', 'DINERO', 'CANTIDAD', 'TARJETA', 'CUENTA', 'ARGENT', 'MONTANT', 'COMPTE', 'GELD', 'BETRAG', 'KONTO'],
|
|
2816
|
-
ADDRESS: ['ADDRESS', 'ADDRESSES', 'STREET', 'STREET_ADDRESS', 'CITY', 'STATE', 'ZIP', 'ZIPCODE', 'ZIP_CODE', 'COUNTRY', 'LOCATION', 'АДРЕС', 'АДРЕСА', 'УЛИЦА', 'ГОРОД', 'СТРАНА', 'DIRECCION', 'DIRECCIONES', 'CALLE', 'CIUDAD', 'PAIS', 'ADRESSE', 'ADRESSES', 'RUE', 'VILLE', 'STRASSE', 'STADT', 'LAND'],
|
|
2817
|
-
DATE: ['DATE', 'DATES', 'BIRTHDAY', 'DOB', 'ДАТА', 'ДАТЫ', 'ДЕНЬ_РОЖДЕНИЯ', 'FECHA', 'FECHAS', 'CUMPLEANOS', 'ANNIVERSAIRE', 'DATUM', 'DATEN', 'GEBURTSTAG'],
|
|
2818
|
-
PHI: ['PHI', 'MRN', 'NHS', 'HEALTH', 'MEDICAL', 'PATIENT', 'МЕД', 'ПАЦИЕНТ', '
|
|
2819
|
-
SECRET: ['SECRET', 'SECRETS', 'KEY', 'KEYS', 'TOKEN', 'TOKENS', 'PASSWORD', 'PASSWORDS', 'AUTH', 'APIKEY', 'API_KEY', 'КЛЮЧ', 'КЛЮЧИ', 'ПАРОЛЬ', 'ПАРОЛИ', 'ТОКЕН', 'CLAVE', 'CONTRASENA', 'CLE', 'MOT_DE_PASSE', 'SCHLUESSEL', 'PASSWORT'],
|
|
2820
|
-
CUSTOM: ['CUSTOM', 'CUSTOMS', 'RULE', 'RULES', 'КАСТОМ', 'ПРАВИЛО']
|
|
3135
|
+
NAME: ['NAME', 'NAMES', 'USERNAME', 'USER_NAME', 'USER', 'USERS', 'CLIENTNAME', 'CLIENT_NAME', 'CANDIDATE_NAME', 'FULL_NAME', 'FIRSTNAME', 'FIRST_NAME', 'LASTNAME', 'LAST_NAME', 'SURNAME', 'PATIENT', 'PACIENTE', 'DOUTOR', 'MEDICO', 'MÉDICO', 'PRENOM', 'PRÉNOM', 'ИМЯ', 'ИМЕНА', 'ПОЛЬЗОВАТЕЛЬ', 'ФИО', 'КЛИЕНТ', 'NOMBRE', 'NOMBRES', 'USUARIO', 'CLIENTE', 'NOM', 'NOMS', 'UTILISATEUR', 'NAMEN', 'BENUTZER', 'KUNDE', 'NOME', 'NOMES', 'SOBRENOME', 'COGNOME', 'UTENTE', 'NAAM', 'GEBRUIKER', 'KLANT', 'שם', 'שמות', 'משתמש', 'לקוח'],
|
|
3136
|
+
EMAIL: ['EMAIL', 'EMAILS', 'EMAILADDR', 'EMAIL_ADDR', 'EMAILADDRESS', 'EMAIL_ADDRESS', 'EMAIL_ADR', 'MAIL', 'MAILS', 'E-MAIL', 'E_MAIL', 'ПОЧТА', 'ЭЛ_ПОЧТА', 'АДРЕС_ПОЧТЫ', 'МЕЙЛ', 'МАЙЛ', 'CORREO', 'COURRIEL', 'CORREO_ELECTRONICO', 'CORREIO', 'MEL', 'אימייל', 'דואל', 'מייל'],
|
|
3137
|
+
PHONE: ['PHONE', 'PHONES', 'PHONENUM', 'PHONE_NUM', 'PHONENUMBER', 'PHONE_NUMBER', 'TEL', 'TELS', 'TELEPHONE', 'TELEPHONES', 'TÉLÉPHONE', 'TELEFONE', 'CELULAR', 'MOBILE', 'CELL', 'ТЕЛЕФОН', 'ТЕЛЕФОНЫ', 'НОМЕР_ТЕЛЕФОНА', 'НОМЕР', 'MOVIL', 'MÓVIL', 'PORTABLE', 'HANDY', 'TELEFONI', 'CELLULARE', 'טלפון', 'נייד'],
|
|
3138
|
+
ID: ['ID', 'IDS', 'IDNUM', 'ID_NUM', 'IDNUMBER', 'ID_NUMBER', 'IDENTIFIER', 'IDENTIFIERS', 'ARN', 'ARNS', 'PASSPORT', 'SSN', 'EIN', 'TAXID', 'TAX_ID', 'CPF', 'CNPJ', 'RG', 'CRM', 'LICENSE', 'LICENSE_PLATE', 'DEMOGRAPHIC', 'DEMOGRAPHICS', 'NUMERO', 'NUMÉRO', 'NÚMERO', 'ИД', 'ИДЕНТИФИКАТОР', 'ПАСПОРТ', 'СНИЛС', 'ИНН', 'IDENTIFICADOR', 'PASAPORTE', 'IDENTIFIANT', 'PASSEPORT', 'IDENTIFIKATOR', 'PASS', 'IDENTIFICATORE', 'PASSAPORTO', 'PASSAPORTE', 'תז', 'תעודת_זהות', 'מזהה', 'דרכון'],
|
|
3139
|
+
FINANCIAL: ['FINANCIAL', 'FINANCIALS', 'MONEY', 'AMOUNT', 'PRICE', 'COST', 'CARD', 'CREDITCARD', 'DEBITCARD', 'ACCOUNT', 'IBAN', 'BIC', 'VALOR', 'CONTA', 'CARTAO', 'CARTÃO', 'ДЕНЬГИ', 'СУММА', 'КАРТА', 'СЧЕТ', 'БАНК', 'DINERO', 'CANTIDAD', 'TARJETA', 'CUENTA', 'ARGENT', 'MONTANT', 'COMPTE', 'GELD', 'BETRAG', 'KONTO', 'פיננסי', 'סכום', 'חשבון', 'כרטיס'],
|
|
3140
|
+
ADDRESS: ['ADDRESS', 'ADDRESSES', 'STREET', 'STREET_ADDRESS', 'CITY', 'STATE', 'ZIP', 'ZIPCODE', 'ZIP_CODE', 'CEP', 'COUNTRY', 'LOCATION', 'ENDERECO', 'ENDEREÇO', 'RUA', 'CIDADE', 'АДРЕС', 'АДРЕСА', 'УЛИЦА', 'ГОРОД', 'СТРАНА', 'DIRECCION', 'DIRECCIÓN', 'DIRECCIONES', 'CALLE', 'CIUDAD', 'PAIS', 'PAÍS', 'ADRESSE', 'ADRESSES', 'RUE', 'VILLE', 'STRASSE', 'STADT', 'LAND', 'כתובת', 'עיר', 'רחוב'],
|
|
3141
|
+
DATE: ['DATE', 'DATES', 'BIRTHDAY', 'DOB', 'DATA', 'DATAS', 'NASCIMENTO', 'DATA_NASCIMENTO', 'ДАТА', 'ДАТЫ', 'ДЕНЬ_РОЖДЕНИЯ', 'FECHA', 'FECHAS', 'CUMPLEANOS', 'CUMPLEAÑOS', 'ANNIVERSAIRE', 'DATUM', 'DATEN', 'GEBURTSTAG', 'תאריך', 'תאריך_לידה'],
|
|
3142
|
+
PHI: ['PHI', 'MRN', 'NHS', 'CNS', 'SUS', 'PRONTUARIO', 'PRONTUÁRIO', 'HEALTH', 'MEDICAL', 'PATIENT', 'PACIENTE', 'МЕД', 'ПАЦИЕНТ', 'מטופל', 'רפואי'],
|
|
3143
|
+
SECRET: ['SECRET', 'SECRETS', 'KEY', 'KEYS', 'TOKEN', 'TOKENS', 'PASSWORD', 'PASSWORDS', 'AUTH', 'APIKEY', 'API_KEY', 'SENHA', 'SEGREDO', 'CHAVE', 'КЛЮЧ', 'КЛЮЧИ', 'ПАРОЛЬ', 'ПАРОЛИ', 'ТОКЕН', 'CLAVE', 'CONTRASENA', 'CONTRASEÑA', 'CLE', 'CLÉ', 'MOT_DE_PASSE', 'SCHLUESSEL', 'SCHLÜSSEL', 'PASSWORT', 'סוד', 'סיסמה', 'מפתח'],
|
|
3144
|
+
CUSTOM: ['CUSTOM', 'CUSTOMS', 'RULE', 'RULES', 'КАСТОМ', 'ПРАВИЛО', 'מותאם']
|
|
2821
3145
|
};
|
|
2822
3146
|
|
|
2823
3147
|
function getLabelAliases(label) {
|
|
@@ -2875,16 +3199,16 @@ const PROFILE_JARGON = {
|
|
|
2875
3199
|
const regexParts = [];
|
|
2876
3200
|
|
|
2877
3201
|
sortedKeys.forEach(k => {
|
|
2878
|
-
const inner = k.replace(/^\[|<|\{\{|__|\]|>|\}\}|__/g, '');
|
|
3202
|
+
const inner = k.replace(/^\[|<|\{\{?|\(|__|\]|>|\}\}?|\)|__/g, '');
|
|
2879
3203
|
const match = inner.match(/^([A-Za-z_0-9]+?)[-_]?(\d+)$/);
|
|
2880
3204
|
if (match) {
|
|
2881
3205
|
const label = match[1];
|
|
2882
3206
|
const baseIndex = parseInt(match[2], 10);
|
|
2883
3207
|
const aliases = getLabelAliases(label);
|
|
2884
3208
|
|
|
2885
|
-
const escapedAliases = aliases.map(a => a.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
3209
|
+
const escapedAliases = aliases.map(a => a.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/[_-]/g, '\\\\?[_-]'));
|
|
2886
3210
|
const aliasesGroup = `(?:${escapedAliases.join('|')})`;
|
|
2887
|
-
const loosePattern = `(?:\\[\\s*${aliasesGroup}[-_
|
|
3211
|
+
const loosePattern = `(?:(?:\\[|\\\\u005[Bb]|%5[Bb]|&(?:amp;)?#0*91;|&(?:amp;)?#[xX]0*5[Bb];|&(?:amp;)?lbrack;|【|[|〔|「|『)\\s*[*` + '`' + `~]*${aliasesGroup}[-_\\\\\\s]*0*${baseIndex}[*` + '`' + `~]*[.,;:!?]?\\s*(?:\\]|\\\\u005[Dd]|%5[Dd]|&(?:amp;)?#0*93;|&(?:amp;)?#[xX]0*5[Dd];|&(?:amp;)?rbrack;|】|]|〕|」|』)|<\\s*${aliasesGroup}[-_\\\\\\s]*0*${baseIndex}[.,;:!?]?\\s*>|\\{\\{?\\s*${aliasesGroup}[-_\\\\\\s]*0*${baseIndex}[.,;:!?]?\\s*\\}\\}?|__\\s*${aliasesGroup}[-_\\\\\\s]*0*${baseIndex}\\s*__|(?<![A-Za-z0-9\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF_])${aliasesGroup}[-_\\\\\\s]*0*${baseIndex}(?![A-Za-z0-9\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF_]))(?:'s|’s|s|[а-яёА-ЯЁ]{1,3})?`;
|
|
2888
3212
|
looseRules.push({ token: k, pattern: loosePattern });
|
|
2889
3213
|
}
|
|
2890
3214
|
regexParts.push(k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
@@ -2892,7 +3216,7 @@ const PROFILE_JARGON = {
|
|
|
2892
3216
|
|
|
2893
3217
|
let compositeRegex = null;
|
|
2894
3218
|
if (regexParts.length > 0) {
|
|
2895
|
-
compositeRegex = new RegExp(`(?:\\b|\\[
|
|
3219
|
+
compositeRegex = new RegExp(`(?:\\b|\\[|\\\\u005[Bb]|%5[Bb]|&(?:amp;)?#0*91;|&(?:amp;)?#[xX]0*5[Bb];|&(?:amp;)?lbrack;|【|[|〔|「|『|<|\\{\\{?|__)?(?:(?:(?<!\\w)|(?<=\\s))(?:${regexParts.join('|')})(?:(?!\\w)|(?=\\s)))(?:\\b|\\]|\\\\u005[Dd]|%5[Dd]|&(?:amp;)?#0*93;|&(?:amp;)?#[xX]0*5[Dd];|&(?:amp;)?rbrack;|】|]|〕|」|』|>|\\}\\}?|__)?(?:'s|’s|s|[а-яёА-ЯЁ]{1,3})?`, 'g');
|
|
2896
3220
|
}
|
|
2897
3221
|
|
|
2898
3222
|
return { compositeRegex, looseRules };
|
|
@@ -2918,8 +3242,8 @@ const PROFILE_JARGON = {
|
|
|
2918
3242
|
// If text is a full valid JSON object or array, preserve structure
|
|
2919
3243
|
if (!isJsonPayload(cleaned)) {
|
|
2920
3244
|
// 1. Strip raw CSS / style blocks leaked from ChatGPT Canvas, web components or stylesheets (handles multi-line, unclosed and variable definitions)
|
|
2921
|
-
cleaned = cleaned.replace(/^\s*(?:[.#][a-zA-Z0-9_-]+|\[[a-zA-Z0-9_#.:\-*>=,'"\s]+\]|:is\([^)]+\)|[a-zA-Z0-9_-]+)?\s*\{[^}]*?(?:\}\s*|\n\n+|$)/gi, "");
|
|
2922
|
-
cleaned = cleaned.replace(/^[;
|
|
3245
|
+
cleaned = cleaned.replace(/^\s*(?:[.#][a-zA-Z0-9_-]+|\[[a-zA-Z0-9_#.:\-*>=,'"\s]+\]|:is\([^)]+\)|[a-zA-Z0-9_-]+)?\s*\{[^}:]*:[^}]*?(?:\}\s*|\n\n+|$)/gi, "");
|
|
3246
|
+
cleaned = cleaned.replace(/^[; \t\r\n]+/, "");
|
|
2923
3247
|
cleaned = cleaned.replace(/(?:^|\n)[a-zA-Z0-9_#.:\-*>[\]=\s,'"]+\{[^}]*(--[a-zA-Z0-9_-]+:|color-mix\(|var\()[^}]*\}/g, "");
|
|
2924
3248
|
}
|
|
2925
3249
|
// 2. Strip AI author prefixes and platform artifacts
|
|
@@ -2927,12 +3251,14 @@ const PROFILE_JARGON = {
|
|
|
2927
3251
|
cleaned = cleaned.replace(/^(?:Here (?:is|are) (?:the )?(?:redacted|scrubbed|sanitized|processed|clean|updated|modified) (?:text|output|version|data).*?[:\n]+|\*\*Scrubbed Text\*\*[:\n]+|### Scrubbed Text[:\n]+)/i, '');
|
|
2928
3252
|
cleaned = cleaned.replace(/^\s*Edit\s*\n+/i, "");
|
|
2929
3253
|
cleaned = cleaned.replace(/\s*\bEdit\s+in\s+a\s+page\b\s*$/i, "");
|
|
2930
|
-
// 3. Strip echoed system instructions and PrivacyScrubber pseudonymization disclaimers
|
|
3254
|
+
// 3. Strip echoed system instructions and PrivacyScrubber / ZTDS pseudonymization disclaimers
|
|
2931
3255
|
cleaned = cleaned.replace(/^\s*(?:Understood|Acknowledged|Got it|Sure|OK|Okay|Note taken|Understood[.,!])[^\n]*\n+/i, "");
|
|
2932
|
-
cleaned = cleaned.replace(/(?:^|\n*)\s*\[(?:Privacy Note|Context: identifiers|Privacy Scrubber Mode|SYSTEM INSTRUCTION: DATA PRIVACY MODE)[\s\S]*?
|
|
2933
|
-
cleaned = cleaned.replace(/(?:^|\n*)\s*\[(?:Privacy Note|Context: identifiers|Privacy Scrubber Mode|SYSTEM INSTRUCTION: DATA PRIVACY MODE)[^\]]*\]\s*(?:\n*|$)/gi, "\n\n");
|
|
2934
|
-
cleaned = cleaned.replace(/(?:^|\n*)\s*(?:Direct identifiers in this prompt were pseudonymized|I will retain all bracketed tokens)[^\n]*(?:\n*|$)/gi, "\n\n");
|
|
3256
|
+
cleaned = cleaned.replace(/(?:^|\n*)\s*(?:----------------------\s*\n*)?\[(?:ZTDS(?:™|\(TM\))?\s*Protocol|Privacy Note|Context: identifiers|Privacy Scrubber Mode|SYSTEM INSTRUCTION: DATA PRIVACY MODE)[\s\S]*?(?:in your response\.?\]|(?:\]\s*(?:\n*----------------------\s*)?))(?:\n*|$)/gi, "\n\n");
|
|
3257
|
+
cleaned = cleaned.replace(/(?:^|\n*)\s*(?:----------------------\s*\n*)?\[(?:ZTDS(?:™|\(TM\))?\s*Protocol|Privacy Note|Context: identifiers|Privacy Scrubber Mode|SYSTEM INSTRUCTION: DATA PRIVACY MODE|Secured by PrivacyScrubber)[^\n\]]*\]\s*(?:\n*----------------------\s*)?(?:\n*|$)/gi, "\n\n");
|
|
3258
|
+
cleaned = cleaned.replace(/(?:^|\n*)\s*(?:Direct identifiers in this prompt were (?:pseudonymized|client-side sanitized)|I will retain all bracketed tokens)[^\n]*(?:\n*|$)/gi, "\n\n");
|
|
2935
3259
|
// 4. Strip stray leading colons, semicolons, or separators left by stripped icons/artifact headers
|
|
3260
|
+
cleaned = cleaned.replace(/^(?:\s*----------------------\s*\n+)+/, "");
|
|
3261
|
+
cleaned = cleaned.replace(/(?:\n+\s*----------------------\s*)+$/, "");
|
|
2936
3262
|
cleaned = cleaned.replace(/^[:;|\-\—\–]+(?=\n|$)/, "");
|
|
2937
3263
|
cleaned = cleaned.replace(/^[:;]+\s*/, "");
|
|
2938
3264
|
return cleaned.trim();
|
|
@@ -2960,7 +3286,7 @@ const PROFILE_JARGON = {
|
|
|
2960
3286
|
lookup.set(k, v);
|
|
2961
3287
|
lookup.set(k.toUpperCase(), v);
|
|
2962
3288
|
|
|
2963
|
-
const inner = k.replace(/^\[|<|\{\{
|
|
3289
|
+
const inner = k.replace(/^\[|<|\{\{?|__|\]|>|\}\}?|__/g, '');
|
|
2964
3290
|
const match = inner.match(/^([A-Za-z_0-9]+?)[-_]?(\d+)$/);
|
|
2965
3291
|
if (match) {
|
|
2966
3292
|
const label = match[1];
|
|
@@ -2972,9 +3298,15 @@ const PROFILE_JARGON = {
|
|
|
2972
3298
|
u + ' ' + baseIndex,
|
|
2973
3299
|
u + baseIndex,
|
|
2974
3300
|
'[' + u + '_' + baseIndex + ']',
|
|
3301
|
+
'[' + u + baseIndex + ']',
|
|
2975
3302
|
'<' + u + '_' + baseIndex + '>',
|
|
3303
|
+
'<' + u + baseIndex + '>',
|
|
2976
3304
|
'{{' + u + '_' + baseIndex + '}}',
|
|
3305
|
+
'{{' + u + baseIndex + '}}',
|
|
3306
|
+
'{' + u + '_' + baseIndex + '}',
|
|
3307
|
+
'{' + u + baseIndex + '}',
|
|
2977
3308
|
'__' + u + '_' + baseIndex + '__',
|
|
3309
|
+
'__' + u + baseIndex + '__',
|
|
2978
3310
|
'[' + u + ' ' + baseIndex + ']',
|
|
2979
3311
|
'[' + u + '-' + baseIndex + ']'
|
|
2980
3312
|
];
|
|
@@ -2990,7 +3322,7 @@ const PROFILE_JARGON = {
|
|
|
2990
3322
|
for (let i = 0; i < keys.length; i++) {
|
|
2991
3323
|
const k = keys[i];
|
|
2992
3324
|
const v = sessionMap[k];
|
|
2993
|
-
const inner = k.replace(/^\[|<|\{\{
|
|
3325
|
+
const inner = k.replace(/^\[|<|\{\{?|__|\]|>|\}\}?|__/g, '');
|
|
2994
3326
|
const match = inner.match(/^([A-Za-z_0-9]+?)[-_]?(\d+)$/);
|
|
2995
3327
|
if (match) {
|
|
2996
3328
|
const label = match[1];
|
|
@@ -3005,9 +3337,15 @@ const PROFILE_JARGON = {
|
|
|
3005
3337
|
u + ' ' + baseIndex,
|
|
3006
3338
|
u + baseIndex,
|
|
3007
3339
|
'[' + u + '_' + baseIndex + ']',
|
|
3340
|
+
'[' + u + baseIndex + ']',
|
|
3008
3341
|
'<' + u + '_' + baseIndex + '>',
|
|
3342
|
+
'<' + u + baseIndex + '>',
|
|
3009
3343
|
'{{' + u + '_' + baseIndex + '}}',
|
|
3344
|
+
'{{' + u + baseIndex + '}}',
|
|
3345
|
+
'{' + u + '_' + baseIndex + '}',
|
|
3346
|
+
'{' + u + baseIndex + '}',
|
|
3010
3347
|
'__' + u + '_' + baseIndex + '__',
|
|
3348
|
+
'__' + u + baseIndex + '__',
|
|
3011
3349
|
'[' + u + ' ' + baseIndex + ']',
|
|
3012
3350
|
'[' + u + '-' + baseIndex + ']'
|
|
3013
3351
|
];
|
|
@@ -3021,7 +3359,7 @@ const PROFILE_JARGON = {
|
|
|
3021
3359
|
}
|
|
3022
3360
|
}
|
|
3023
3361
|
|
|
3024
|
-
let regexStr = '(?:\\[\\s*[A-Za-z0-9_
|
|
3362
|
+
let regexStr = '(?:(?:\\[|\\\\u005[Bb]|%5[Bb]|&(?:amp;)?#0*91;|&(?:amp;)?#[xX]0*5[Bb];|&(?:amp;)?lbrack;|【|[|〔|「|『)\\s*[*`~]*[A-Za-z0-9_\\\\\\-\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF ]+[*`~]*[.,;:!?]?\\s*(?:\\]|\\\\u005[Dd]|%5[Dd]|&(?:amp;)?#0*93;|&(?:amp;)?#[xX]0*5[Dd];|&(?:amp;)?rbrack;|】|]|〕|」|』)|<\\s*[A-Za-z0-9_\\\\\\-\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF ]+[.,;:!?]?\\s*>|\\{\\{?\\s*[A-Za-z0-9_\\\\\\-\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF ]+[.,;:!?]?\\s*\\}\\}?|__\\s*[A-Za-z0-9_\\\\\\-\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF ]+\\s*__|(?<=^|[^a-zA-Z0-9_\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF])[A-Za-z_\\\\\\u00C0-\\u024F\\u0400-\\u04FF\\u0590-\\u05FF]+[-_\\\\\\s]*\\d+)';
|
|
3025
3363
|
if (customRegexParts.length > 0) {
|
|
3026
3364
|
regexStr = '(?:' + regexStr + '|' + customRegexParts.join('|') + ')';
|
|
3027
3365
|
}
|
|
@@ -3034,13 +3372,15 @@ const PROFILE_JARGON = {
|
|
|
3034
3372
|
return entry;
|
|
3035
3373
|
}
|
|
3036
3374
|
|
|
3375
|
+
const OUTER_TOKEN_DELIM_RE = /^(?:\[|\\u005[Bb]|%5[Bb]|&(?:amp;)?#0*91;|&(?:amp;)?#[xX]0*5[Bb];|&(?:amp;)?lbrack;|【|[|〔|「|『|<|\{\{?|__)\s*|\s*(?:\]|\\u005[Dd]|%5[Dd]|&(?:amp;)?#0*93;|&(?:amp;)?#[xX]0*5[Dd];|&(?:amp;)?rbrack;|】|]|〕|」|』|>|\}\}?|__)$/gi;
|
|
3376
|
+
|
|
3037
3377
|
function resolveTokenValue(rawMatch, targetTokenKey, sessionMap) {
|
|
3038
3378
|
if (!sessionMap) return undefined;
|
|
3039
3379
|
if (sessionMap[targetTokenKey] !== undefined) return sessionMap[targetTokenKey];
|
|
3040
3380
|
if (sessionMap[rawMatch] !== undefined) return sessionMap[rawMatch];
|
|
3041
|
-
const cleanRaw = rawMatch.replace(
|
|
3381
|
+
const cleanRaw = rawMatch.replace(OUTER_TOKEN_DELIM_RE, '').replace(/\\([_-])/g, '$1').replace(/[*`~]+/g, '').replace(/[.,;:!?]+$/, '').trim();
|
|
3042
3382
|
for (const k of Object.keys(sessionMap)) {
|
|
3043
|
-
const cleanK = k.replace(/^\[|<|\{\{
|
|
3383
|
+
const cleanK = k.replace(/^\[|<|\{\{?|__|\]|>|\}\}?|__/g, '').trim();
|
|
3044
3384
|
if (cleanK.toLowerCase() === cleanRaw.toLowerCase()) {
|
|
3045
3385
|
return sessionMap[k];
|
|
3046
3386
|
}
|
|
@@ -3067,22 +3407,26 @@ const PROFILE_JARGON = {
|
|
|
3067
3407
|
restoredCount++;
|
|
3068
3408
|
return lookup.get(upper);
|
|
3069
3409
|
}
|
|
3070
|
-
// Normalized lookup: strip outer brackets/delimiters,
|
|
3071
|
-
const
|
|
3072
|
-
const
|
|
3410
|
+
// Normalized lookup: strip outer brackets/delimiters (including URL-encoded, JSON Unicode escapes, HTML entities, CJK fullwidth/corner) and Markdown wrappers
|
|
3411
|
+
const rawInner = match.replace(OUTER_TOKEN_DELIM_RE, '').replace(/\\([_-])/g, '$1').replace(/[*`~]+/g, '').trim();
|
|
3412
|
+
const innerPunctMatch = rawInner.match(/^([\s\S]+?)([.,;:!?])$/);
|
|
3413
|
+
const inner = innerPunctMatch ? innerPunctMatch[1].trim() : rawInner;
|
|
3414
|
+
const trailingPunct = innerPunctMatch ? innerPunctMatch[2] : '';
|
|
3415
|
+
const normMatch = inner.match(/^([A-Za-z_\u00C0-\u024F\u0400-\u04FF\u0590-\u05FF0-9]+?)[-_\s]*0*(\d+)$/);
|
|
3073
3416
|
if (normMatch) {
|
|
3074
3417
|
const normLabel = normMatch[1].replace(/[\s_-]+/g, '_').toUpperCase();
|
|
3075
3418
|
const normIdx = parseInt(normMatch[2], 10);
|
|
3076
3419
|
const candidates = [
|
|
3077
3420
|
normLabel + '_' + normIdx,
|
|
3078
3421
|
'[' + normLabel + '_' + normIdx + ']',
|
|
3422
|
+
'[' + normLabel + normIdx + ']',
|
|
3079
3423
|
normLabel + ' ' + normIdx,
|
|
3080
3424
|
normLabel + '-' + normIdx
|
|
3081
3425
|
];
|
|
3082
3426
|
for (let c = 0; c < candidates.length; c++) {
|
|
3083
3427
|
if (lookup.has(candidates[c])) {
|
|
3084
3428
|
restoredCount++;
|
|
3085
|
-
return lookup.get(candidates[c]);
|
|
3429
|
+
return lookup.get(candidates[c]) + trailingPunct;
|
|
3086
3430
|
}
|
|
3087
3431
|
}
|
|
3088
3432
|
}
|
|
@@ -3131,14 +3475,18 @@ const PROFILE_JARGON = {
|
|
|
3131
3475
|
} else if (lookup.has(match.toUpperCase())) {
|
|
3132
3476
|
rawVal = lookup.get(match.toUpperCase());
|
|
3133
3477
|
} else {
|
|
3134
|
-
const
|
|
3135
|
-
const
|
|
3478
|
+
const rawInner = match.replace(OUTER_TOKEN_DELIM_RE, '').replace(/\\([_-])/g, '$1').replace(/[*`~]+/g, '').trim();
|
|
3479
|
+
const innerPunctMatch = rawInner.match(/^([\s\S]+?)([.,;:!?])$/);
|
|
3480
|
+
const inner = innerPunctMatch ? innerPunctMatch[1].trim() : rawInner;
|
|
3481
|
+
if (innerPunctMatch) suffix = innerPunctMatch[2];
|
|
3482
|
+
const normMatch = inner.match(/^([A-Za-z_\u00C0-\u024F\u0400-\u04FF\u0590-\u05FF0-9]+?)[-_\s]*0*(\d+)$/);
|
|
3136
3483
|
if (normMatch) {
|
|
3137
3484
|
const normLabel = normMatch[1].replace(/[\s_-]+/g, '_').toUpperCase();
|
|
3138
3485
|
const normIdx = parseInt(normMatch[2], 10);
|
|
3139
3486
|
const candidates = [
|
|
3140
3487
|
normLabel + '_' + normIdx,
|
|
3141
3488
|
'[' + normLabel + '_' + normIdx + ']',
|
|
3489
|
+
'[' + normLabel + normIdx + ']',
|
|
3142
3490
|
normLabel + ' ' + normIdx,
|
|
3143
3491
|
normLabel + '-' + normIdx
|
|
3144
3492
|
];
|
|
@@ -3162,7 +3510,7 @@ const PROFILE_JARGON = {
|
|
|
3162
3510
|
if (rawVal !== null) {
|
|
3163
3511
|
restoredCount++;
|
|
3164
3512
|
const escapedVal = escapeHTML(rawVal);
|
|
3165
|
-
const cleanMatch = match.replace(
|
|
3513
|
+
const cleanMatch = match.replace(OUTER_TOKEN_DELIM_RE, '').replace(/[*`~]+/g, '').replace(/[.,;:!?]+$/, '').trim();
|
|
3166
3514
|
return `<span class="ps-restored-data entity-tag entity-revealed" title="Original Token: ${escapeHTML(cleanMatch)}">${escapedVal}</span>${escapeHTML(suffix)}`;
|
|
3167
3515
|
}
|
|
3168
3516
|
return match;
|
|
@@ -3177,14 +3525,17 @@ const PROFILE_JARGON = {
|
|
|
3177
3525
|
const suffixMatch = match.match(/(?:'s|’s|s|[а-яёА-ЯЁ]{1,3})$/);
|
|
3178
3526
|
const suffix = suffixMatch ? suffixMatch[0] : '';
|
|
3179
3527
|
const baseMatch = suffix ? match.slice(0, -suffix.length) : match;
|
|
3180
|
-
const
|
|
3528
|
+
const rawClean = baseMatch.replace(OUTER_TOKEN_DELIM_RE, '').replace(/[*`~]+/g, '').trim();
|
|
3529
|
+
const punctMatch = rawClean.match(/^([\s\S]+?)([.,;:!?])$/);
|
|
3530
|
+
const cleanMatch = punctMatch ? punctMatch[1].trim() : rawClean;
|
|
3531
|
+
const innerPunct = punctMatch ? punctMatch[2] : '';
|
|
3181
3532
|
const token = `[${cleanMatch}]`;
|
|
3182
3533
|
|
|
3183
3534
|
const val = resolveTokenValue(baseMatch, token, sessionMap) ?? resolveTokenValue(baseMatch, cleanMatch, sessionMap);
|
|
3184
3535
|
if (val !== undefined) {
|
|
3185
3536
|
restoredCount++;
|
|
3186
3537
|
const escapedVal = escapeHTML(val);
|
|
3187
|
-
return `<span class="ps-restored-data entity-tag entity-revealed" title="Original Token: ${escapeHTML(token)}">${escapedVal}</span>${escapeHTML(suffix)}`;
|
|
3538
|
+
return `<span class="ps-restored-data entity-tag entity-revealed" title="Original Token: ${escapeHTML(token)}">${escapedVal}</span>${escapeHTML(innerPunct + suffix)}`;
|
|
3188
3539
|
}
|
|
3189
3540
|
return match;
|
|
3190
3541
|
});
|
|
@@ -3201,12 +3552,15 @@ const PROFILE_JARGON = {
|
|
|
3201
3552
|
const suffixMatch = match.match(/(?:'s|’s|s|[а-яёА-ЯЁ]{1,3})$/);
|
|
3202
3553
|
const suffix = suffixMatch ? suffixMatch[0] : '';
|
|
3203
3554
|
const baseMatch = suffix ? match.slice(0, -suffix.length) : match;
|
|
3555
|
+
const rawClean = baseMatch.replace(OUTER_TOKEN_DELIM_RE, '').replace(/[*`~]+/g, '').trim();
|
|
3556
|
+
const punctMatch = rawClean.match(/^([\s\S]+?)([.,;:!?])$/);
|
|
3557
|
+
const innerPunct = punctMatch ? punctMatch[2] : '';
|
|
3204
3558
|
|
|
3205
3559
|
const val = sessionMap[rule.token] ?? resolveTokenValue(baseMatch, rule.token, sessionMap);
|
|
3206
3560
|
if (val !== undefined) {
|
|
3207
3561
|
restoredCount++;
|
|
3208
3562
|
const escapedVal = escapeHTML(val);
|
|
3209
|
-
return `<span class="ps-restored-data entity-tag entity-revealed" title="Original Token: ${escapeHTML(rule.token)} (Fuzzy Match)">${escapedVal}</span>${escapeHTML(suffix)}`;
|
|
3563
|
+
return `<span class="ps-restored-data entity-tag entity-revealed" title="Original Token: ${escapeHTML(rule.token)} (Fuzzy Match)">${escapedVal}</span>${escapeHTML(innerPunct + suffix)}`;
|
|
3210
3564
|
}
|
|
3211
3565
|
return match;
|
|
3212
3566
|
});
|