Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [2.6.7] - 2026-07

### Fixed
- **PIB preceded by service labels / noise is now masked.** In lines like
`ПІБ: Петренко Іван Васильович` or log lines
`… ІПН=3698521592 — ПІБ «138» → «Міронов Андрій Петрович» …` the real name
was skipped: the PIB anchor latched onto `ІПН=…` (starts uppercase) or the
marker `ПІБ`, then stopped. Now `is_pib_anchor` strips trailing punctuation
and rejects tokens containing digits/`=`; `ПІБ` and `звання` are excluded
markers.

### Known limitation
- A bare rank with **no** following PIB (e.g. `звання «…» → «молодший сержант»`)
is still not masked — long-standing behavior that avoids false positives on
rank words in prose; independent of this fix.

## [2.6.6] - 2026-06

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion data_masking.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
# Re-exports from masking package for backward compatibility
# ============================================================================

__version__ = "2.6.6"
__version__ = "2.6.7"

from masking.constants import (
__version__, __author__, __contact__, __phone__, __license__, __year__,
Expand Down
5 changes: 4 additions & 1 deletion masking/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# ============================================================================
# МЕТАДАНІ
# ============================================================================
__version__ = "2.6.6"
__version__ = "2.6.7"
__author__ = "Vladyslav V. Prodan"
__contact__ = "github.com/click0"
__phone__ = "+38(099)6053340"
Expand Down Expand Up @@ -129,6 +129,9 @@
"неналежііе", "инутрішньої", "радіовіzUділення",
"с~гатуту", "року", "Року", "числа", "місяця",
"один", "два", "три", "чотири", "п'ять",
# Службові маркери-мітки (щоб не плутались із самим ПІБ у форматах
# "ПІБ: Петренко..." чи логах "ПІБ «138» → «Міронов...»")
"ПІБ", "піб", "Піб", "звання", "Звання", "ЗВАННЯ",
]

# Regex паттерни для виявлення звань різних типів служб
Expand Down
4 changes: 3 additions & 1 deletion masking/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ def normalize_identifier(identifier: str) -> str:

def is_pib_anchor(word: str) -> bool:
if word.startswith("___") and word.endswith("___"): return False
word = word.strip(_cfg.QUOTE_CHARS)
word = word.strip(_cfg.QUOTE_CHARS).strip(",.!?;:")
if not word or len(word) <= 2: return False
# Слова з цифрами/= — не ПІБ (ІПН=3698521592, «138», кодування)
if re.search(r'[\d=]', word): return False
word_lower = word.lower()
if word_lower in _cfg.EXCLUDE_WORDS_LOWER: return False
if word_lower in _cfg.RANKS_LIST_LOWER: return False
Expand Down
26 changes: 26 additions & 0 deletions tests/test_quoted.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,29 @@ def test_matches_unquoted_behaviour(self):
a, _ = mask('Петренко Іван Сергійович')
b, _ = mask('«Петренко Іван Сергійович»')
assert b == '«' + a + '»'


class TestServiceMarkers:
"""ПІБ маскується, коли перед ним стоять службові мітки/шум
("ПІБ:", "ІПН=…", лог-формати), а не сам ПІБ."""

def test_label_pib_colon(self):
masked, _ = mask('ПІБ: Петренко Іван Васильович')
assert 'Петренко' not in masked
assert masked.startswith('ПІБ: ') # мітка лишається

def test_data_ipn_log_line(self):
line = ('[WARNING] data-ipn: ІПН=3698521592 — ПІБ «138» → '
'«Міронов Андрій Петрович» (джерело data-ipn головне)')
masked, md = mask(line)
assert 'Міронов' not in masked
assert '3698521592' not in masked # ІПН теж
from unmasking.engine import unmask_text_v2
restored, _ = unmask_text_v2(masked, md, check_mapping_version(md))
assert restored == line

def test_ipn_assignment_not_treated_as_name(self):
# ІПН=NNNNNNNNNN не має ламати розпізнавання ПІБ далі в рядку
masked, _ = mask('ІПН=1234567890 Петренко Іван Васильович')
assert 'Петренко' not in masked
assert '1234567890' not in masked
2 changes: 1 addition & 1 deletion unmasking/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
# ============================================================================
# МЕТАДАНІ
# ============================================================================
__version__ = "2.6.6"
__version__ = "2.6.7"


def main():
Expand Down
Loading