feat: клавиши (Ctrl/Alt/Del) в исключения + подсветка маркером только переменной
- IGNORED_OLD_VARS: <Ctrl>, <Alt>, <Del> и др. клавиши больше не
считаются незаменёнными переменными (7.6 Инструкция Пользователя)
- Подсветка: вместо красного цвета текста — красный маркер
(w:highlight) на самой переменной, а не на всём абзаце
- OLD_VAR_MAP: ShortCompanyName1-6 (склонения краткого названия),
IspdnName → {{is_name_1}}
This commit is contained in:
+62
-19
@@ -30,6 +30,17 @@ VAR_PATTERN = re.compile(r'\{\{[^}]+\}\}')
|
|||||||
OLD_VAR_PATTERN = re.compile(r'<[A-Za-z0-9_]+>')
|
OLD_VAR_PATTERN = re.compile(r'<[A-Za-z0-9_]+>')
|
||||||
UNMATCHED_PATTERN = re.compile(r'\{\{[^}]+\}\}|<[A-Za-z0-9_]+>')
|
UNMATCHED_PATTERN = re.compile(r'\{\{[^}]+\}\}|<[A-Za-z0-9_]+>')
|
||||||
|
|
||||||
|
# «Переменные», которые на самом деле не переменные, а клавиши в тексте
|
||||||
|
# инструкций (Ctrl+Alt+Del и т.п.) — их не считаем незаменёнными
|
||||||
|
IGNORED_OLD_VARS = {
|
||||||
|
'<Ctrl>', '<Alt>', '<Del>', '<Delete>', '<Shift>', '<Enter>', '<Tab>',
|
||||||
|
'<Esc>', '<Escape>', '<Insert>', '<Home>', '<End>', '<PageUp>', '<PageDown>',
|
||||||
|
'<Backspace>', '<Space>', '<CapsLock>', '<NumLock>', '<ScrollLock>',
|
||||||
|
'<PrintScreen>', '<Pause>', '<Break>', '<Up>', '<Down>', '<Left>', '<Right>',
|
||||||
|
'<F1>', '<F2>', '<F3>', '<F4>', '<F5>', '<F6>', '<F7>', '<F8>', '<F9>',
|
||||||
|
'<F10>', '<F11>', '<F12>',
|
||||||
|
}
|
||||||
|
|
||||||
LOOP_START = re.compile(r'(?:<!--|<!--)\s*loop:(\w+)\s*(?:-->|-->)')
|
LOOP_START = re.compile(r'(?:<!--|<!--)\s*loop:(\w+)\s*(?:-->|-->)')
|
||||||
LOOP_END = re.compile(r'(?:<!--|<!--)\s*loop_end\s*(?:-->|-->)')
|
LOOP_END = re.compile(r'(?:<!--|<!--)\s*loop_end\s*(?:-->|-->)')
|
||||||
|
|
||||||
@@ -61,6 +72,14 @@ OLD_VAR_MAP = {
|
|||||||
'<DocumentNumber>': '{{document_number}}',
|
'<DocumentNumber>': '{{document_number}}',
|
||||||
'<DocumentDate>': '{{document_date}}',
|
'<DocumentDate>': '{{document_date}}',
|
||||||
'<Date>': '{{date}}',
|
'<Date>': '{{date}}',
|
||||||
|
# Краткое наименование по падежам (старые шаблоны)
|
||||||
|
'<ShortCompanyName1>': '{{company_short_name}}',
|
||||||
|
'<ShortCompanyName2>': '{{company_short_name_genitive}}',
|
||||||
|
'<ShortCompanyName3>': '{{company_short_name_dative}}',
|
||||||
|
'<ShortCompanyName4>': '{{company_short_name_accs}}',
|
||||||
|
'<ShortCompanyName5>': '{{company_short_name_ablt}}',
|
||||||
|
'<ShortCompanyName6>': '{{company_short_name_loct}}',
|
||||||
|
'<IspdnName>': '{{is_name_1}}',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -342,42 +361,64 @@ def _strip_prooferr(doc):
|
|||||||
|
|
||||||
|
|
||||||
def _highlight_unmatched(doc):
|
def _highlight_unmatched(doc):
|
||||||
"""Подсвечивает незаменённые переменные красным."""
|
"""Выделяет незаменённые переменные красным маркером (только саму переменную)."""
|
||||||
ns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
|
ns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
|
||||||
|
|
||||||
def _highlight_run(run):
|
def _apply_highlight(run_el):
|
||||||
rpr = run._element.find(f'{{{ns}}}rPr')
|
rpr = run_el.find(f'{{{ns}}}rPr')
|
||||||
if rpr is None:
|
if rpr is None:
|
||||||
rpr = OxmlElement('w:rPr')
|
rpr = OxmlElement('w:rPr')
|
||||||
run._element.insert(0, rpr)
|
run_el.insert(0, rpr)
|
||||||
color = OxmlElement('w:color')
|
hl = OxmlElement('w:highlight')
|
||||||
color.set(f'{{{ns}}}val', 'FF0000')
|
hl.set(f'{{{ns}}}val', 'red')
|
||||||
rpr.append(color)
|
rpr.append(hl)
|
||||||
|
|
||||||
|
def _process_para(para):
|
||||||
|
full = para.text
|
||||||
|
matches = [m for m in UNMATCHED_PATTERN.finditer(full)
|
||||||
|
if m.group(0) not in IGNORED_OLD_VARS]
|
||||||
|
if not matches:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Пересобираем параграф: обычный текст и переменные отдельными run'ами,
|
||||||
|
# переменные — с красным маркером. Сохраняем стиль первого run.
|
||||||
|
first = para.runs[0] if para.runs else None
|
||||||
|
para.clear()
|
||||||
|
pos = 0
|
||||||
|
for m in matches:
|
||||||
|
if m.start() > pos:
|
||||||
|
run = para.add_run(full[pos:m.start()])
|
||||||
|
if first is not None:
|
||||||
|
_copy_run_style(first, run)
|
||||||
|
run = para.add_run(m.group(0))
|
||||||
|
if first is not None:
|
||||||
|
_copy_run_style(first, run)
|
||||||
|
_apply_highlight(run._element)
|
||||||
|
pos = m.end()
|
||||||
|
if pos < len(full):
|
||||||
|
run = para.add_run(full[pos:])
|
||||||
|
if first is not None:
|
||||||
|
_copy_run_style(first, run)
|
||||||
|
|
||||||
for para in doc.paragraphs:
|
for para in doc.paragraphs:
|
||||||
for run in para.runs:
|
_process_para(para)
|
||||||
if UNMATCHED_PATTERN.search(run.text or ''):
|
|
||||||
_highlight_run(run)
|
|
||||||
|
|
||||||
for table in doc.tables:
|
for table in doc.tables:
|
||||||
for row in table.rows:
|
for row in table.rows:
|
||||||
for cell in row.cells:
|
for cell in row.cells:
|
||||||
for para in cell.paragraphs:
|
for para in cell.paragraphs:
|
||||||
for run in para.runs:
|
_process_para(para)
|
||||||
if UNMATCHED_PATTERN.search(run.text or ''):
|
|
||||||
_highlight_run(run)
|
|
||||||
|
|
||||||
for section in doc.sections:
|
for section in doc.sections:
|
||||||
for hf in [section.header, section.footer]:
|
for hf in [section.header, section.footer,
|
||||||
if hf:
|
section.first_page_header, section.first_page_footer]:
|
||||||
|
if hf is not None:
|
||||||
for para in hf.paragraphs:
|
for para in hf.paragraphs:
|
||||||
for run in para.runs:
|
_process_para(para)
|
||||||
if UNMATCHED_PATTERN.search(run.text or ''):
|
|
||||||
_highlight_run(run)
|
|
||||||
|
|
||||||
|
|
||||||
def _log_unmatched(doc, replacements=None, log_func=None):
|
def _log_unmatched(doc, replacements=None, log_func=None):
|
||||||
"""Логирует незаменённые переменные."""
|
"""Логирует незаменённые переменные (без клавиш-исключений)."""
|
||||||
if not log_func:
|
if not log_func:
|
||||||
return
|
return
|
||||||
unmatched = []
|
unmatched = []
|
||||||
@@ -385,6 +426,8 @@ def _log_unmatched(doc, replacements=None, log_func=None):
|
|||||||
for para in doc.paragraphs:
|
for para in doc.paragraphs:
|
||||||
for m in UNMATCHED_PATTERN.finditer(para.text):
|
for m in UNMATCHED_PATTERN.finditer(para.text):
|
||||||
var = m.group(0)
|
var = m.group(0)
|
||||||
|
if var in IGNORED_OLD_VARS:
|
||||||
|
continue
|
||||||
if var not in seen:
|
if var not in seen:
|
||||||
seen.add(var)
|
seen.add(var)
|
||||||
unmatched.append(var)
|
unmatched.append(var)
|
||||||
|
|||||||
Reference in New Issue
Block a user