Coverage for presidio_analyzer / predefined_recognizers / country_specific / korea / kr_brn_recognizer.py: 93%

28 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-03-29 09:03 +0000

1from typing import List, Optional, Tuple, Union 

2 

3from presidio_analyzer import EntityRecognizer, Pattern, PatternRecognizer 

4 

5 

6class KrBrnRecognizer(PatternRecognizer): 

7 """ 

8 Recognize Korean Business Registration Number (BRN). 

9 

10 The Korean Business Registration Number (BRN) is a 10-digit number 

11 assigned to businesses in South Korea for taxation purposes. 

12 

13 The format is AAA-BB-CCCCC where: 

14 - AAA: District office code 

15 - BB: Type of business code 

16 - CCCCC: Serial number and check digit 

17 

18 Reference: https://org-id.guide/list/KR-BRN 

19 

20 :param patterns: List of patterns to be used by this recognizer 

21 :param context: List of context words to increase confidence in detection 

22 :param supported_language: Language this recognizer supports 

23 :param supported_entity: The entity this recognizer can detect 

24 :param replacement_pairs: List of tuples with potential replacement values 

25 to be used during pattern matching (e.g., removing dashes). 

26 """ 

27 

28 PATTERNS = [ 

29 Pattern( 

30 "BRN (Weak)", 

31 r"(?<!\d)\d{3}-\d{2}-\d{5}(?!\d)", 

32 0.1, 

33 ), 

34 Pattern( 

35 "BRN (Very weak)", 

36 r"(?<!\d)\d{10}(?!\d)", 

37 0.05, 

38 ), 

39 ] 

40 

41 CONTEXT = [ 

42 "사업자등록번호", 

43 "사업자번호", 

44 "사업자", 

45 "BRN", 

46 "Business Registration Number", 

47 "Korean BRN", 

48 "business number", 

49 "tax registration number", 

50 ] 

51 

52 def __init__( 

53 self, 

54 patterns: Optional[List[Pattern]] = None, 

55 context: Optional[List[str]] = None, 

56 supported_language: str = "ko", 

57 supported_entity: str = "KR_BRN", 

58 replacement_pairs: Optional[List[Tuple[str, str]]] = None, 

59 ): 

60 self.replacement_pairs = replacement_pairs if replacement_pairs else [("-", "")] 

61 

62 patterns = patterns if patterns else self.PATTERNS 

63 context = context if context else self.CONTEXT 

64 super().__init__( 

65 supported_entity=supported_entity, 

66 patterns=patterns, 

67 context=context, 

68 supported_language=supported_language, 

69 ) 

70 

71 def validate_result(self, pattern_text: str) -> Union[bool, None]: 

72 """ 

73 Validate the pattern logic by running a checksum on a detected BRN. 

74 

75 :param pattern_text: The text detected by the regex engine. 

76 :return: True if validation is successful, False otherwise. 

77 """ 

78 # Sanitize the value by removing dashes 

79 sanitized_value = EntityRecognizer.sanitize_value( 

80 pattern_text, self.replacement_pairs 

81 ) 

82 

83 # BRN must be exactly 10 digits 

84 if len(sanitized_value) != 10: 

85 return False 

86 

87 if not sanitized_value.isdigit(): 

88 return False 

89 

90 return self._validate_checksum(sanitized_value) 

91 

92 def _validate_checksum(self, brn: str) -> bool: 

93 """ 

94 Validate the checksum of Korean Business Registration Number. 

95 

96 The validation algorithm: 

97 1. Multiply the first 9 digits by the magic keys: [1, 3, 7, 1, 3, 7, 1, 3, 5]. 

98 2. Sum the results of the first 8 multiplications. 

99 3. For the 9th digit (index 8): 

100 Add the product (digit * 5) AND the quotient of (digit * 5) / 10 to the sum. 

101 4. Take the remainder of the total sum divided by 10. 

102 5. Subtract the remainder from 10. 

103 The result (mod 10) should match the 10th digit. 

104 

105 :param brn: The 10-digit BRN string to validate. 

106 :return: True if checksum is valid, False otherwise. 

107 """ 

108 digits = [int(d) for d in brn] 

109 magic_keys = [1, 3, 7, 1, 3, 7, 1, 3, 5] 

110 

111 # Step 1 & 2: Calculate sum for the first 8 digits 

112 total_sum = 0 

113 for i in range(8): 

114 total_sum += digits[i] * magic_keys[i] 

115 

116 # Step 3: Special handling for the 9th digit 

117 last_key_mul = digits[8] * magic_keys[8] 

118 total_sum += (last_key_mul // 10) + last_key_mul 

119 

120 # Step 4 & 5: Validate against the 10th check digit 

121 remainder = total_sum % 10 

122 check_digit = (10 - remainder) % 10 

123 

124 return check_digit == digits[9]