From 1b4012091284a842dab2cb3e06f63ab9a5423dd9 Mon Sep 17 00:00:00 2001 From: AtomicGlance Date: Wed, 12 Aug 2026 10:26:15 +0330 Subject: [PATCH 1/5] Add UK and India national ID formats --- docs/dqx/docs/reference/quality_checks.mdx | 2 +- src/databricks/labs/dqx/check_funcs.py | 27 +++++++++++++---- tests/unit/test_row_checks.py | 34 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/docs/dqx/docs/reference/quality_checks.mdx b/docs/dqx/docs/reference/quality_checks.mdx index 160a16e4c..1d4944cae 100644 --- a/docs/dqx/docs/reference/quality_checks.mdx +++ b/docs/dqx/docs/reference/quality_checks.mdx @@ -61,7 +61,7 @@ You can also define your own custom checks in Python (see [Creating custom check | `regex_match` | Checks whether the values in the input column match a given regex. | `column`: column to check (can be a string column name or a column expression); regex: regex to check; `negate`: if the condition should be negated (true) or not | | `is_valid_email` | Checks whether the values in the input column have valid email address format. | `column`: column to check (can be a string column name or a column expression) | | `has_valid_string_case` | Checks whether string values match the requested letter case: `upper` requires all alphabetic characters to be uppercase; `lower` requires all alphabetic characters to be lowercase; `title` requires the first character of each space-delimited word to be uppercase; `sentence` requires each period-delimited segment's first non-whitespace character to be uppercase. | `column`: column to check (can be a string column name or a column expression); `case`: one of `upper`, `lower`, `title`, or `sentence` | -| `is_valid_national_id` | Checks whether the values in the input column are valid national identification numbers (e.g., US Social Security Numbers) for the given country. | `column`: column to check (can be a string column name or a column expression); `country`: ISO 3166 alpha-2 country code (optional, default: `US`) | +| `is_valid_national_id` | Checks whether the values in the input column match a supported national identification number format. Supports US Social Security Numbers (`US`), UK National Insurance numbers (`GB`), and Indian Permanent Account Numbers (`IN`). These are format checks only; they do not verify whether an identifier was issued. | `column`: column to check (can be a string column name or a column expression); `country`: ISO 3166 alpha-2 country code (optional, default: `US`) | | `is_valid_uuid` | Checks whether the values in the input column are valid UUIDs (RFC 9562, canonical 8-4-4-4-12 hyphenated hex form). By default validates the shape only; set `strict` to also enforce the version nibble (1-8) and variant bits per RFC 9562. | `column`: column to check (can be a string column name or a column expression); `strict`: if True, also validate the version nibble (1-8) and variant bits (8/9/a/b) per RFC 9562 (default: False) | | `is_valid_country_code` | Checks whether the values in the input column are valid ISO 3166-1 country codes (alpha-2, e.g. US, alpha-3, e.g. USA, or numeric, e.g. 840). Source: https://www.iso.org/iso-3166-country-codes.html | `column`: column to check (can be a string column name or a column expression); `code_format`: ISO 3166-1 representation, `alpha-2` (default), `alpha-3`, or `numeric`; `case_sensitive`: optional boolean flag for case-sensitive comparison (default: True) | | `is_valid_currency_code` | Checks whether the values in the input column are valid ISO 4217 currency codes (alphabetic, e.g. USD, or numeric, e.g. 840). Source: https://www.iso.org/iso-4217-currency-codes.html | `column`: column to check (can be a string column name or a column expression); `code_format`: ISO 4217 representation, `alphabetic` (default) or `numeric`; `case_sensitive`: optional boolean flag for case-sensitive comparison (default: True) | diff --git a/src/databricks/labs/dqx/check_funcs.py b/src/databricks/labs/dqx/check_funcs.py index ad8d9d39d..91faf89be 100644 --- a/src/databricks/labs/dqx/check_funcs.py +++ b/src/databricks/labs/dqx/check_funcs.py @@ -117,6 +117,15 @@ class DQPattern(Enum): # none) must be consistent via backreference \1. Excludes invalid ranges - area # 000/666/9xx (9xx covers ITINs), group 00, serial 0000. Anchored, fixed-width; ReDoS-safe. SSN_US = r"\A(?!000|666|9\d{2})\d{3}([- ]?)(?!00)\d{2}\1(?!0000)\d{4}\z" + # UK National Insurance Number: two-letter prefix, six digits, and an A-D + # suffix. Exclude prefixes that HMRC does not allocate. + NINO_GB = ( + r"\A(?!(?:BG|GB|KN|NK|NT|TN|ZZ))(?!(?:[DFIQUV]))[A-Z]" + r"(?![DFIOQUV])[A-Z] ?\d{2} ?\d{2} ?\d{2} ?[ABCD]\z" + ) + # Indian Permanent Account Number (PAN): five letters, four digits, and a + # final letter. + PAN_IN = r"\A[A-Z]{5}\d{4}[A-Z]\z" # Canonical UUID form per RFC 9562: 8-4-4-4-12 hex groups. UUID validates the shape # only, so RFC-defined Nil/Max sentinels and legacy variant GUIDs pass; UUID_STRICT @@ -130,6 +139,8 @@ class DQPattern(Enum): # alpha-2 code here. _NATIONAL_ID_PATTERNS_BY_COUNTRY: dict[str, DQPattern] = { "US": DQPattern.SSN_US, + "GB": DQPattern.NINO_GB, + "IN": DQPattern.PAN_IN, } @@ -1173,12 +1184,16 @@ def is_valid_national_id(column: str | Column, country: str = "US") -> Column: Validation is limited to *format* and *number ranges*; it does not verify that a number was actually issued. - Supported countries are keyed by ISO 3166 alpha-2 code. Currently only *US* is - supported: the *AAA-GG-SSSS* form is required, where the separators may be all - hyphens, all single spaces, or omitted entirely (e.g. *123-45-6789*, *123 45 6789* - or *123456789*), but must be used consistently. Structurally invalid ranges are - rejected (area *000*, *666* and *900-999* - the latter covering ITINs; group *00*; - serial *0000*). + Supported countries are keyed by ISO 3166 alpha-2 code. For *US*, the + *AAA-GG-SSSS* form is required, where the separators may be all hyphens, all + single spaces, or omitted entirely (e.g. *123-45-6789*, *123 45 6789* or + *123456789*), but must be used consistently. Structurally invalid ranges are + rejected (area *000*, *666* and *900-999* - the latter covering ITINs; group + *00*; serial *0000*). For *GB*, a National Insurance number consists of two + letters, six digits, and a final *A*, *B*, *C*, or *D*; unallocated prefixes + are rejected. For *IN*, a PAN consists of five letters, four digits, and a + final letter. These checks validate format only, not whether an identifier + was issued. Null values will pass the check with no violation reported. diff --git a/tests/unit/test_row_checks.py b/tests/unit/test_row_checks.py index 60e79cfff..90549ec0d 100644 --- a/tests/unit/test_row_checks.py +++ b/tests/unit/test_row_checks.py @@ -1,7 +1,10 @@ +import re from typing import cast import pytest from databricks.labs.dqx.utils import get_column_name_or_alias from databricks.labs.dqx.check_funcs import ( + DQPattern, + _pattern_for_python_re, is_equal_to, is_not_equal_to, is_in_range, @@ -197,6 +200,37 @@ def test_is_valid_national_id_country_is_case_insensitive(): assert get_column_name_or_alias(result) == "a_does_not_match_pattern_ssn_us" +def test_is_valid_national_id_supports_uk_nino(): + result = is_valid_national_id("a", country="GB") + assert get_column_name_or_alias(result) == "a_does_not_match_pattern_nino_gb" + + +def test_is_valid_national_id_supports_indian_pan(): + result = is_valid_national_id("a", country="IN") + assert get_column_name_or_alias(result) == "a_does_not_match_pattern_pan_in" + + +@pytest.mark.parametrize( + "value", + ["AB123456A", "AB 12 34 56 A", "BX586745C"], +) +def test_nino_pattern_accepts_valid_formats(value): + assert re.fullmatch(_pattern_for_python_re(DQPattern.NINO_GB), value) + + +@pytest.mark.parametrize("value", ["DF123456A", "BG123456A", "AB123456E"]) +def test_nino_pattern_rejects_invalid_prefixes_and_suffixes(value): + assert not re.fullmatch(_pattern_for_python_re(DQPattern.NINO_GB), value) + + +def test_pan_pattern_accepts_ten_character_format(): + assert re.fullmatch(_pattern_for_python_re(DQPattern.PAN_IN), "ABCDE1234F") + + +def test_pan_pattern_rejects_wrong_character_positions(): + assert not re.fullmatch(_pattern_for_python_re(DQPattern.PAN_IN), "AB12E1234F") + + def test_is_valid_national_id_missing_country(): with pytest.raises(MissingParameterError, match="'country' is not provided."): is_valid_national_id("a", country=None) From 02512c4d43f74e826b79509b3fef09acb98c0659 Mon Sep 17 00:00:00 2001 From: AtomicGlance Date: Wed, 12 Aug 2026 23:22:44 +0330 Subject: [PATCH 2/5] Address national ID review feedback --- src/databricks/labs/dqx/check_funcs.py | 16 +++---- tests/integration/test_row_checks.py | 62 ++++++++++++++++++++++++++ tests/unit/test_row_checks.py | 34 -------------- 3 files changed, 70 insertions(+), 42 deletions(-) diff --git a/src/databricks/labs/dqx/check_funcs.py b/src/databricks/labs/dqx/check_funcs.py index 91faf89be..696b2480a 100644 --- a/src/databricks/labs/dqx/check_funcs.py +++ b/src/databricks/labs/dqx/check_funcs.py @@ -120,12 +120,11 @@ class DQPattern(Enum): # UK National Insurance Number: two-letter prefix, six digits, and an A-D # suffix. Exclude prefixes that HMRC does not allocate. NINO_GB = ( - r"\A(?!(?:BG|GB|KN|NK|NT|TN|ZZ))(?!(?:[DFIQUV]))[A-Z]" - r"(?![DFIOQUV])[A-Z] ?\d{2} ?\d{2} ?\d{2} ?[ABCD]\z" + r"\A(?!(?:BG|GB|KN|NK|NT|TN|ZZ))(?!(?:[DFIQUV]))[A-Z]" r"(?![DFIOQUV])[A-Z] ?\d{2} ?\d{2} ?\d{2} ?[ABCD]\z" ) - # Indian Permanent Account Number (PAN): five letters, four digits, and a - # final letter. - PAN_IN = r"\A[A-Z]{5}\d{4}[A-Z]\z" + # Indian Permanent Account Number (PAN): three letters, a holder-type letter, + # another letter, four digits, and a final letter. + PAN_IN = r"\A[A-Z]{3}[ABCFGHJLPT][A-Z]\d{4}[A-Z]\z" # Canonical UUID form per RFC 9562: 8-4-4-4-12 hex groups. UUID validates the shape # only, so RFC-defined Nil/Max sentinels and legacy variant GUIDs pass; UUID_STRICT @@ -1191,9 +1190,10 @@ def is_valid_national_id(column: str | Column, country: str = "US") -> Column: rejected (area *000*, *666* and *900-999* - the latter covering ITINs; group *00*; serial *0000*). For *GB*, a National Insurance number consists of two letters, six digits, and a final *A*, *B*, *C*, or *D*; unallocated prefixes - are rejected. For *IN*, a PAN consists of five letters, four digits, and a - final letter. These checks validate format only, not whether an identifier - was issued. + are rejected. For *IN*, a PAN consists of three letters, a holder-type letter + (*A*, *B*, *C*, *F*, *G*, *H*, *J*, *L*, *P*, or *T*), another letter, four + digits, and a final letter. These checks validate format only, not whether an + identifier was issued. Null values will pass the check with no violation reported. diff --git a/tests/integration/test_row_checks.py b/tests/integration/test_row_checks.py index df4013a12..2cc268d99 100644 --- a/tests/integration/test_row_checks.py +++ b/tests/integration/test_row_checks.py @@ -2298,6 +2298,68 @@ def violation(value: str) -> str: assertDataFrameEqual(actual, expected) + schema_nino = "nino: string" + nino_df = spark.createDataFrame( + [ + ["AB123456A"], + ["AB 12 34 56 A"], + ["BX586745C"], + ["DF123456A"], # invalid first letter + ["BG123456A"], # unallocated prefix + ["AB123456E"], # invalid suffix + [None], + ], + schema_nino, + ) + nino_actual = nino_df.select(is_valid_national_id("nino", country="GB")) + + def nino_violation(value: str) -> str: + return f"Value '{value}' in Column 'nino' does not match pattern 'NINO_GB'" + + nino_expected = spark.createDataFrame( + [ + [None], + [None], + [None], + [nino_violation("DF123456A")], + [nino_violation("BG123456A")], + [nino_violation("AB123456E")], + [None], + ], + "nino_does_not_match_pattern_nino_gb: string", + ) + assertDataFrameEqual(nino_actual, nino_expected) + + schema_pan = "pan: string" + pan_df = spark.createDataFrame( + [ + ["ABCPD1234F"], + ["AACTA1234A"], + ["ABCZD1234F"], # Z is not a valid holder type + ["AB12E1234F"], # letters and digits in the wrong positions + ["ABCPD12345"], # final character must be a letter + [None], + ], + schema_pan, + ) + pan_actual = pan_df.select(is_valid_national_id("pan", country="IN")) + + def pan_violation(value: str) -> str: + return f"Value '{value}' in Column 'pan' does not match pattern 'PAN_IN'" + + pan_expected = spark.createDataFrame( + [ + [None], + [None], + [pan_violation("ABCZD1234F")], + [pan_violation("AB12E1234F")], + [pan_violation("ABCPD12345")], + [None], + ], + "pan_does_not_match_pattern_pan_in: string", + ) + assertDataFrameEqual(pan_actual, pan_expected) + def test_col_is_valid_national_id_column_expr_and_lowercase_country(spark): schema_ssn = "a: string" diff --git a/tests/unit/test_row_checks.py b/tests/unit/test_row_checks.py index 90549ec0d..60e79cfff 100644 --- a/tests/unit/test_row_checks.py +++ b/tests/unit/test_row_checks.py @@ -1,10 +1,7 @@ -import re from typing import cast import pytest from databricks.labs.dqx.utils import get_column_name_or_alias from databricks.labs.dqx.check_funcs import ( - DQPattern, - _pattern_for_python_re, is_equal_to, is_not_equal_to, is_in_range, @@ -200,37 +197,6 @@ def test_is_valid_national_id_country_is_case_insensitive(): assert get_column_name_or_alias(result) == "a_does_not_match_pattern_ssn_us" -def test_is_valid_national_id_supports_uk_nino(): - result = is_valid_national_id("a", country="GB") - assert get_column_name_or_alias(result) == "a_does_not_match_pattern_nino_gb" - - -def test_is_valid_national_id_supports_indian_pan(): - result = is_valid_national_id("a", country="IN") - assert get_column_name_or_alias(result) == "a_does_not_match_pattern_pan_in" - - -@pytest.mark.parametrize( - "value", - ["AB123456A", "AB 12 34 56 A", "BX586745C"], -) -def test_nino_pattern_accepts_valid_formats(value): - assert re.fullmatch(_pattern_for_python_re(DQPattern.NINO_GB), value) - - -@pytest.mark.parametrize("value", ["DF123456A", "BG123456A", "AB123456E"]) -def test_nino_pattern_rejects_invalid_prefixes_and_suffixes(value): - assert not re.fullmatch(_pattern_for_python_re(DQPattern.NINO_GB), value) - - -def test_pan_pattern_accepts_ten_character_format(): - assert re.fullmatch(_pattern_for_python_re(DQPattern.PAN_IN), "ABCDE1234F") - - -def test_pan_pattern_rejects_wrong_character_positions(): - assert not re.fullmatch(_pattern_for_python_re(DQPattern.PAN_IN), "AB12E1234F") - - def test_is_valid_national_id_missing_country(): with pytest.raises(MissingParameterError, match="'country' is not provided."): is_valid_national_id("a", country=None) From 24598158e6e1106bb1bf5e251e5a00471a00f78c Mon Sep 17 00:00:00 2001 From: AtomicGlance Date: Fri, 14 Aug 2026 11:25:43 +0330 Subject: [PATCH 3/5] Improve national ID integration coverage --- tests/integration/test_row_checks.py | 192 +++++++++++---------------- 1 file changed, 75 insertions(+), 117 deletions(-) diff --git a/tests/integration/test_row_checks.py b/tests/integration/test_row_checks.py index 2cc268d99..c8fe2bd7c 100644 --- a/tests/integration/test_row_checks.py +++ b/tests/integration/test_row_checks.py @@ -2237,128 +2237,86 @@ def violation(value: str) -> str: assertDataFrameEqual(actual, expected) -def test_col_is_valid_national_id(spark): - schema_ssn = "a: string" - test_df = spark.createDataFrame( - [ - # Valid - separators must be consistent (all '-', all ' ', or none) - ["123-45-6789"], - ["123456789"], - ["123 45 6789"], - ["899-45-6789"], # area boundary just below 900 - ["667-45-6789"], # area just above 666 - ["001-01-0001"], # minimal valid area / group / serial - # Invalid - excluded number ranges - ["000-45-6789"], # area 000 - ["666-45-6789"], # area 666 - ["900-45-6789"], # area 9xx (ITIN range, rejected) - ["123-00-6789"], # group 00 - ["123-45-0000"], # serial 0000 - # Invalid - separator / structure - ["123-45 6789"], # mixed separators - ["12-45-6789"], # area too short - ["1234-45-6789"], # area too long - ["abc-de-fghi"], # non-numeric - [""], # empty string - [None], # Null - passes (no violation reported) - ], - schema_ssn, - ) - - actual = test_df.select(is_valid_national_id("a", country="US")) +@pytest.mark.parametrize( + "country, pattern_name, cases", + [ + pytest.param( + "US", + "SSN_US", + [ + # Valid - separators must be consistent (all '-', all ' ', or none) + ("123-45-6789", False), + ("123456789", False), + ("123 45 6789", False), + ("899-45-6789", False), # area boundary just below 900 + ("667-45-6789", False), # area just above 666 + ("001-01-0001", False), # minimal valid area / group / serial + # Invalid - excluded number ranges + ("000-45-6789", True), # area 000 + ("666-45-6789", True), # area 666 + ("900-45-6789", True), # area 9xx (ITIN range, rejected) + ("123-00-6789", True), # group 00 + ("123-45-0000", True), # serial 0000 + # Invalid - separator / structure + ("123-45 6789", True), # mixed separators + ("12-45-6789", True), # area too short + ("1234-45-6789", True), # area too long + ("abc-de-fghi", True), # non-numeric + ("", True), + (None, False), + ], + id="us-ssn", + ), + pytest.param( + "GB", + "NINO_GB", + [ + ("AB123456A", False), + ("AB 12 34 56 A", False), + ("BX586745C", False), + ("DF123456A", True), # invalid first letter + ("BG123456A", True), # unallocated prefix + ("AB123456E", True), # invalid suffix + ("", True), + ("AB123456A\n", True), + (" AB123456A", True), + ("AB123456A ", True), + (None, False), + ], + id="gb-nino", + ), + pytest.param( + "IN", + "PAN_IN", + [ + ("ABCPD1234F", False), + ("AACTA1234A", False), + ("ABCZD1234F", True), # Z is not a valid holder type + ("AB12E1234F", True), # letters and digits in the wrong positions + ("ABCPD12345", True), # final character must be a letter + ("", True), + ("ABCPD1234F\n", True), + (" ABCPD1234F", True), + ("ABCPD1234F ", True), + (None, False), + ], + id="in-pan", + ), + ], +) +def test_col_is_valid_national_id(spark, country, pattern_name, cases): + test_df = spark.createDataFrame([[value] for value, _ in cases], "a: string") + actual = test_df.select(is_valid_national_id("a", country=country)) def violation(value: str) -> str: - return f"Value '{value}' in Column 'a' does not match pattern 'SSN_US'" - - checked_schema = "a_does_not_match_pattern_ssn_us: string" - checked_data = [ - # Valid (no violation reported) - [None], - [None], - [None], - [None], - [None], - [None], - # Invalid - excluded number ranges - [violation("000-45-6789")], - [violation("666-45-6789")], - [violation("900-45-6789")], - [violation("123-00-6789")], - [violation("123-45-0000")], - # Invalid - separator / structure - [violation("123-45 6789")], - [violation("12-45-6789")], - [violation("1234-45-6789")], - [violation("abc-de-fghi")], - [violation("")], - # Null passes - [None], - ] - expected = spark.createDataFrame(checked_data, checked_schema) + return f"Value '{value}' in Column 'a' does not match pattern '{pattern_name}'" - assertDataFrameEqual(actual, expected) - - schema_nino = "nino: string" - nino_df = spark.createDataFrame( - [ - ["AB123456A"], - ["AB 12 34 56 A"], - ["BX586745C"], - ["DF123456A"], # invalid first letter - ["BG123456A"], # unallocated prefix - ["AB123456E"], # invalid suffix - [None], - ], - schema_nino, - ) - nino_actual = nino_df.select(is_valid_national_id("nino", country="GB")) - - def nino_violation(value: str) -> str: - return f"Value '{value}' in Column 'nino' does not match pattern 'NINO_GB'" - - nino_expected = spark.createDataFrame( - [ - [None], - [None], - [None], - [nino_violation("DF123456A")], - [nino_violation("BG123456A")], - [nino_violation("AB123456E")], - [None], - ], - "nino_does_not_match_pattern_nino_gb: string", - ) - assertDataFrameEqual(nino_actual, nino_expected) - - schema_pan = "pan: string" - pan_df = spark.createDataFrame( - [ - ["ABCPD1234F"], - ["AACTA1234A"], - ["ABCZD1234F"], # Z is not a valid holder type - ["AB12E1234F"], # letters and digits in the wrong positions - ["ABCPD12345"], # final character must be a letter - [None], - ], - schema_pan, + expected = spark.createDataFrame( + [[violation(value) if is_invalid else None] for value, is_invalid in cases], + f"a_does_not_match_pattern_{pattern_name.lower()}: string", ) - pan_actual = pan_df.select(is_valid_national_id("pan", country="IN")) - - def pan_violation(value: str) -> str: - return f"Value '{value}' in Column 'pan' does not match pattern 'PAN_IN'" - pan_expected = spark.createDataFrame( - [ - [None], - [None], - [pan_violation("ABCZD1234F")], - [pan_violation("AB12E1234F")], - [pan_violation("ABCPD12345")], - [None], - ], - "pan_does_not_match_pattern_pan_in: string", - ) - assertDataFrameEqual(pan_actual, pan_expected) + assertDataFrameEqual(actual, expected) def test_col_is_valid_national_id_column_expr_and_lowercase_country(spark): From 6d15a20cecd581f24517d93168971b2f3da6d0cb Mon Sep 17 00:00:00 2001 From: Greg Hansen Date: Fri, 14 Aug 2026 17:17:00 -0400 Subject: [PATCH 4/5] Format test --- src/databricks/labs/dqx/check_funcs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/databricks/labs/dqx/check_funcs.py b/src/databricks/labs/dqx/check_funcs.py index 696b2480a..7937cf9c7 100644 --- a/src/databricks/labs/dqx/check_funcs.py +++ b/src/databricks/labs/dqx/check_funcs.py @@ -120,7 +120,7 @@ class DQPattern(Enum): # UK National Insurance Number: two-letter prefix, six digits, and an A-D # suffix. Exclude prefixes that HMRC does not allocate. NINO_GB = ( - r"\A(?!(?:BG|GB|KN|NK|NT|TN|ZZ))(?!(?:[DFIQUV]))[A-Z]" r"(?![DFIOQUV])[A-Z] ?\d{2} ?\d{2} ?\d{2} ?[ABCD]\z" + r"\A(?!(?:BG|GB|KN|NK|NT|TN|ZZ))(?!(?:[DFIQUV]))[A-Z](?![DFIOQUV])[A-Z] ?\d{2} ?\d{2} ?\d{2} ?[ABCD]\z" ) # Indian Permanent Account Number (PAN): three letters, a holder-type letter, # another letter, four digits, and a final letter. From 33855b7e6f15817ac5b281a45bc384de1382a4b0 Mon Sep 17 00:00:00 2001 From: Greg Hansen Date: Fri, 14 Aug 2026 17:34:07 -0400 Subject: [PATCH 5/5] Format test --- src/databricks/labs/dqx/check_funcs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/databricks/labs/dqx/check_funcs.py b/src/databricks/labs/dqx/check_funcs.py index 7937cf9c7..52441ff60 100644 --- a/src/databricks/labs/dqx/check_funcs.py +++ b/src/databricks/labs/dqx/check_funcs.py @@ -119,9 +119,7 @@ class DQPattern(Enum): SSN_US = r"\A(?!000|666|9\d{2})\d{3}([- ]?)(?!00)\d{2}\1(?!0000)\d{4}\z" # UK National Insurance Number: two-letter prefix, six digits, and an A-D # suffix. Exclude prefixes that HMRC does not allocate. - NINO_GB = ( - r"\A(?!(?:BG|GB|KN|NK|NT|TN|ZZ))(?!(?:[DFIQUV]))[A-Z](?![DFIOQUV])[A-Z] ?\d{2} ?\d{2} ?\d{2} ?[ABCD]\z" - ) + NINO_GB = r"\A(?!(?:BG|GB|KN|NK|NT|TN|ZZ))(?!(?:[DFIQUV]))[A-Z](?![DFIOQUV])[A-Z] ?\d{2} ?\d{2} ?\d{2} ?[ABCD]\z" # Indian Permanent Account Number (PAN): three letters, a holder-type letter, # another letter, four digits, and a final letter. PAN_IN = r"\A[A-Z]{3}[ABCFGHJLPT][A-Z]\d{4}[A-Z]\z"