This commit is contained in:
igor04091968
2026-05-13 07:22:27 +03:00
parent 2e5242f5ba
commit eb09251118
11 changed files with 433 additions and 16 deletions
@@ -35,3 +35,19 @@ def validate_snils(value: str) -> bool:
if expected == 100:
expected = 0
return checksum == expected
def validate_passport(value: str) -> bool:
"""
Lightweight Russian passport validator:
- expects 10 digits (series+number), optionally with spaces
- rejects obvious invalid placeholders (all same digit, all zeros)
"""
digits = re.sub(r"\D", "", value)
if len(digits) != 10:
return False
if digits == "0000000000":
return False
if len(set(digits)) == 1:
return False
return True
@@ -10,8 +10,8 @@
"description": "СНИЛС"
},
"passport": {
"regex": "\\b\\d{4}\\s?\\d{6}\\b",
"checksum": "none",
"regex": "\\b\\d{4}\\s\\d{6}\\b",
"checksum": "passport",
"description": "Паспорт РФ"
}
}
@@ -4,9 +4,11 @@ from __future__ import annotations
import json
import pathlib
import re
import sys
from typing import Any
from checksum_validator import validate_inn, validate_snils
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent))
from checksum_validator import validate_inn, validate_passport, validate_snils
def _validate(kind: str, value: str) -> bool:
@@ -14,11 +16,17 @@ def _validate(kind: str, value: str) -> bool:
return validate_inn(value)
if kind == "snils":
return validate_snils(value)
if kind == "passport":
return validate_passport(value)
return True
def match_text(text: str, dictionary_path: str) -> list[dict[str, Any]]:
rules = json.loads(pathlib.Path(dictionary_path).read_text(encoding="utf-8"))
def _load_json(path: str) -> dict[str, Any]:
return json.loads(pathlib.Path(path).read_text(encoding="utf-8"))
def match_text_with_dictionary(text: str, dictionary_path: str) -> list[dict[str, Any]]:
rules = _load_json(dictionary_path)
results: list[dict[str, Any]] = []
for name, rule in rules.items():
regex = re.compile(rule["regex"])
@@ -36,3 +44,40 @@ def match_text(text: str, dictionary_path: str) -> list[dict[str, Any]]:
}
)
return results
def match_text_with_regex_pack(text: str, regex_pack_path: str) -> list[dict[str, Any]]:
pack = _load_json(regex_pack_path)
results: list[dict[str, Any]] = []
entries: list[dict[str, Any]] = []
if isinstance(pack.get("rules"), list):
entries = [e for e in pack["rules"] if isinstance(e, dict)]
elif isinstance(pack.get("patterns"), dict):
entries = [{"id": k, **v} for k, v in pack["patterns"].items() if isinstance(v, dict)]
for entry in entries:
rule_id = entry.get("id") or entry.get("name") or "regex-rule"
regex = re.compile(entry["regex"])
for m in regex.finditer(text):
results.append(
{
"name": rule_id,
"description": entry.get("description", rule_id),
"value": m.group(0),
"start": m.start(),
"end": m.end(),
"severity": entry.get("severity", "medium"),
}
)
return results
def match_text(
text: str,
dictionary_path: str | None = None,
regex_pack_path: str | None = None,
) -> dict[str, list[dict[str, Any]]]:
return {
"dictionary_matches": match_text_with_dictionary(text, dictionary_path) if dictionary_path else [],
"regex_matches": match_text_with_regex_pack(text, regex_pack_path) if regex_pack_path else [],
}
@@ -6,6 +6,8 @@ from pathlib import Path
from PIL import Image
import pytesseract
from dictionary_matcher import match_text
def extract_text(image_path: str) -> str:
path = Path(image_path)
@@ -13,3 +15,16 @@ def extract_text(image_path: str) -> str:
return ""
img = Image.open(path)
return pytesseract.image_to_string(img, lang="rus+eng")
def analyze_screenshot(
image_path: str,
dictionary_path: str | None = None,
regex_pack_path: str | None = None,
) -> dict:
text = extract_text(image_path)
if not text:
return {"text": "", "dictionary_matches": [], "regex_matches": []}
result = match_text(text=text, dictionary_path=dictionary_path, regex_pack_path=regex_pack_path)
result["text"] = text
return result