跳到主要内容

lieflat-gongwen

收藏0

基于真实公文全量统计的公文写作 skill。分公文族与党建族两族,覆盖调研报告/领导讲话/工作意见/经验材料/工作方案/经验总结六类公文族文体,加千字级党建/基层经验材料一类,提供可验收的数值参数、骨架公式、标题技法和自动化自检脚本。触发场景:"写一篇调研报告""起草领导讲话""写份工作意见""写篇党建经验材料""把材料写成经验总结""让这篇稿子更有公文味""检查这篇公文的参数对不对"。

让 AI 安装

DDDZZ最新版本 0.1.0更新于 2026-11-03下载 0 次

scripts/check_params.py

21.5 KB
1#!/usr/bin/env python3
2"""公文/党建 参数自检器
3
4设计原则:只判"硬冲突"(文种识别错误),其余仅作对照提示。
5理由:真实公文的个体差异极大(如调研报告"一是二是"从 0 到 20 次都有),
6 用均值当合格线会把好作品判成不合格。本脚本的参考值统一为
7 中位数 + 四分位(p25-p75),与 参数卡.md 完全一致。
8
9用法:
10 python3 check_params.py draft.md --genre 调研报告
11 python3 check_params.py draft.md --genre 短经验材料
12 python3 check_params.py draft.md --match 猜它最像哪个文种
13 python3 check_params.py --list
14"""
15import argparse, json, re, sys
16from pathlib import Path
17
18# ── 语料中位数与常见区间(p25-p75),仅供对照,不作判定 ──
19REF = {
20 '调研报告': dict(n=75, chars=(3108,3820,3492), sent=(45,59,53), h1=(3,3,3), h2=(0,11,9),
21 h3=(0,0,0), yishi=(0,12,9), dun=(19,26,22), qz=(0,2,1), yq=(18,31,26),
22 jy=(2,5,3), pct=(0,1,0)),
23 '领导讲话': dict(n=44, chars=(3100,4200,3700), sent=(48,64,56), h1=(3,3,3), h2=(3,9,5),
24 h3=(0,0,0), yishi=(2,8,5), dun=(18,27,21), qz=(1,3,2), yq=(35,55,45),
25 jy=(0,4,2), pct=(0,0,0)),
26 '工作意见': dict(n=25, chars=(2900,3800,3300), sent=(52,66,58), h1=(4,6,5), h2=(9,14,13),
27 h3=(0,0,0), yishi=(0,3,1), dun=(25,31,28), qz=(1,3,2), yq=(30,55,40),
28 jy=(0,2,1), pct=(0,1,0)),
29 '经验材料': dict(n=22, chars=(2900,4600,3600), sent=(50,63,56), h1=(2,3,2), h2=(0,4,2),
30 h3=(0,3,1), yishi=(2,9,6), dun=(14,23,19), qz=(0,3,1), yq=(12,30,20),
31 jy=(1,5,3), pct=(0,2,1)),
32 '工作方案': dict(n=10, chars=(2700,5000,3600), sent=(45,68,55), h1=(4,6,5), h2=(4,9,8),
33 h3=(5,17,11), yishi=(0,2,1), dun=(14,22,18), qz=(1,4,2), yq=(14,32,22),
34 jy=(3,10,6), pct=(0,1,0)),
35 '经验总结': dict(n=8, chars=(2100,2700,2500), sent=(58,71,64), h1=(3,4,3), h2=(2,6,4),
36 h3=(0,0,0), yishi=(3,8,5), dun=(23,31,27), qz=(0,1,0), yq=(10,20,14),
37 jy=(0,1,0), pct=(0,0,0)),
38 '短经验材料': dict(n=77, chars=(950,1300,1119), sent=(45,57,51), h1=(0,0,0), h2=(0,1,0),
39 h3=(0,0,0), yishi=(0,1,1), dun=(20,27,24), qz=(0,1,0), yq=(1,4,3),
40 jy=(0,1,0), pct=(0,1,0), paras=(5,7,6), para_len=(130,185,156), quote=(10,18,14),
41 quote_long=(1.8,4.0,2.9)),
42}
43
44# ── 硬冲突规则:违反即为文种识别错误,不是风格差异 ──
45# (字段, 判据函数, 报错文案, 依据)
46HARD = {
47 '短经验材料': [
48 ('h1', lambda v: v <= 1, '千字级经验材料不应用多个一级标题', '77篇语料共 3 个一级标题'),
49 ('chars', lambda v: 700 <= v <= 2000, '短经验材料篇幅应在 700-2000 字', '语料区间 558-3022,中位 1119'),
50 ],
51 '经验总结': [
52 ('pct', lambda v: v == 0, '经验总结不用百分比', '8篇语料 100% 零百分比'),
53 ],
54 '领导讲话': [
55 ('h3', lambda v: v == 0, '领导讲话不用三级标题', '44篇语料三级标题总数为 0'),
56 ],
57 '工作意见': [
58 ('h3', lambda v: v <= 2, '工作意见几乎不用三级标题', '25篇语料平均 0.1 个,最多 2 个'),
59 ],
60}
61
62# 跨文体族硬约束(所有公文族文种共用)
63GONGWEN = ['调研报告','领导讲话','工作意见','经验材料','工作方案','经验总结']
64for g in GONGWEN:
65 HARD.setdefault(g, []).append(
66 ('chars', lambda v: v >= 1200, '公文族篇幅不应低于 1200 字(低于此值应按党建族写)',
67 '公文语料最短 1423 字'))
68
69# 软提示:偏离即提醒,但不判错(因真实作品存在合法变体)
70SOFT = {
71 '工作方案': [
72 ('h3', lambda v: v >= 3, '工作方案通常有三级标题("1.")',
73 '语料平均 11.5 个,但 10 篇中 3 篇为 0(存在无三级标题的变体)'),
74 ],
75 '工作意见': [
76 ('h2', lambda v: v >= 5, '工作意见通常有较多二级标题("(一)")',
77 '语料平均 13.2 个,但存在把重点任务拆成多个平行一级标题的扁平变体'),
78 ],
79 '调研报告': [
80 ('yishi', lambda v: v >= 3, '调研报告通常用"一是二是"做段内分层',
81 '语料中位 9 次,但四分之一的作品完全不用'),
82 ],
83}
84
85# ── 重心分布:最重一段占全篇的比例,p25-p75 与中位 ──
86#
87# 数据来源:对 188 篇可切分语料的**全量统计**(含至少两个一级标题者)。
88#
89# ⚠ 不要用 `文章结构模板.md` 里的区间做验收。那份数据来自每文种 3 篇精读
90# 抽样,与全量差异很大:经验材料抽样得 47-59%,全量实为 27-56%(中位 33);
91# 工作意见抽样得 44-53%,全量实为 24-50%(中位 42)。用抽样值当合格线,
92# 真实公文的命中率只有 8%-16%。
93#
94# 因此本项**只作对照提示,不参与硬冲突判定**。个体离散度极大
95# (调研报告最重一段从 17% 到 72% 都有),区间外不等于写错。
96# 它的用途是提醒一种特定失误:该单段独大的文种写成了均衡分布,
97# 或反之——此时通常伴随其他参数同向偏离,两者合看才有意义。
98FOCUS = {
99 '工作方案': (37, 58, 46, '任务段较重'),
100 '工作意见': (24, 50, 42, '任务段较重'),
101 '经验材料': (27, 56, 33, '做法段较重'),
102 '调研报告': (35, 49, 41, '各功能段较均衡'),
103 '经验总结': (29, 42, 36, '各段近乎等重'),
104 '领导讲话': (33, 41, 36, '各段近乎等重'),
105}
106
107ID_PARAM = {
108 '调研报告': '一是二是分层最密 + 建议词最多(向上级建言)',
109 '领导讲话': '要求词密度最高 + 三级标题为 0',
110 '工作意见': '二级标题最多(约13个)+ 几乎不用"一是"',
111 '经验材料': '一级标题最少(约2个),靠段落推进',
112 '工作方案': '三级标题最多(约11个),唯一大量用"1."的文种',
113 '经验总结': '引号概念密度冠军 + 零百分比',
114 '短经验材料': '零一级标题 + 长引号引语多(引群众原话)',
115}
116
117# 法定公文:结构由制度锁定,是固定填空而非写作技法,故不设参数行。
118# 用 --genre 指定这些文种时给出解释,而不是只报"未知文体"。
119NO_PARAM = ('报告', '通知', '请示', '批复', '函', '决定', '条例', '意见', '通报', '纪要')
120
121BAD_WORDS = {
122 '我觉得': '公文不用第一人称主观判断 → 研究认为/实践表明',
123 '我认为': '公文不用第一人称主观判断 → 研究认为/实践表明',
124 '非常': '空洞程度副词 → 用数据或事实替代',
125 '取得了显著成效': '万能废话 → 说清具体成效',
126 '希望领导重视': '太直白 → 用论证逻辑自然导向结论',
127 '问题很多': '缺乏具体性 → 列举具体问题',
128 '尽快': '模糊时限 → 明确到月/日',
129 '相关部门': '模糊主体 → 明确牵头和配合单位',
130}
131
132
133def analyze(text):
134 lines = [l.strip() for l in text.split('\n') if l.strip()]
135 body_lines = []
136 for l in lines:
137 if re.match(r'^#{1,6}\s', l):
138 body_lines.append(re.sub(r'^#{1,6}\s*', '', l))
139 elif re.match(r'^(\||-{3,}|>)', l):
140 continue
141 else:
142 body_lines.append(l)
143 body = '\n'.join(body_lines)
144 plain = re.sub(r'\*\*|__|`', '', body)
145 chars = len(plain.replace('\n', ''))
146 if chars == 0:
147 return None
148
149 sents = [s for s in re.split(r'[。!?;]', plain) if len(s.strip()) >= 4]
150 paras = [l for l in body_lines if len(l) > 40
151 and not re.match(r'^[一二三四五六七八九十]+、|^([一二三四五六七八九十]+)|^\d+[..]', l)]
152
153 h1 = []
154 for m in re.finditer(r'^\**([一二三四五六七八九十]+、)([^\n]{2,80})', body, re.M):
155 t = re.split(r'[。!?;]', m.group(2))[0]
156 t = re.split(r' {2,}|\s{3,}', t)[0]
157 h1.append(t.strip()[:40])
158
159 # 力度词统计前先剔除引号内内容。
160 # 理由:自造概念常带力度字样(如需求分类"必须改""可以缓"),
161 # 计入后会顶破配额。经验总结强制词配额仅 0-1,任何误判都致命。
162 depunct = re.sub(r'[“"][^”"]{0,20}[”"]', '', plain)
163 # "不得不"是"只能"义,不是禁止义,需从"不得"中排除
164 qz_text = depunct.replace('不得不', '###')
165
166 return dict(
167 chars=chars,
168 sent=round(sum(len(s) for s in sents)/len(sents), 1) if sents else 0,
169 h1=len(h1), h1_titles=h1,
170 h2=len(re.findall(r'^\**([一二三四五六七八九十]+)', body, re.M)),
171 h3=len(re.findall(r'^\**\d+[..]\s*\D', body, re.M)),
172 yishi=len(re.findall(r'[一二三四五六七八九]是[,、]?', plain)),
173 dun=round(1000*plain.count('、')/chars, 1),
174 qz=sum(qz_text.count(w) for w in ['应当','必须','不得','严禁']),
175 yq=sum(depunct.count(w) for w in ['要','切实','确保','务必']),
176 jy=sum(depunct.count(w) for w in ['建议','可以','鼓励','支持']),
177 # 占位符内的 % 不是真实数据(如【待补:xx%】),先剔除
178 pct=len(re.findall(r'\d+(?:\.\d+)?%',
179 re.sub(r'【[^】]*】', '', plain))),
180 quote=len(re.findall(r'[“"][^”"]{1,8}[”"]', plain)),
181 # 长引号引语:党建族引群众原话,中位 2.9‰,是它的正向指纹。
182 # 网评族移除后这项不再承担两个千字文体的分界任务,但公文族语料
183 # 无此字段,实测值高仍能把党建族拉近、把公文族推远,保留有效。
184 # 仅统计中文弯引号——ASCII 直角引号无法配对,会把相邻两个引号
185 # 之间的正文误判为引语。
186 quote_long=round(1000*len(re.findall(r'[“][^”]{9,}[”]', plain))/chars, 1),
187 paras=len(paras),
188 para_len=round(sum(len(p) for p in paras)/len(paras)) if paras else 0,
189 ascii_quote=plain.count('"'),
190 dash=plain.count('——'),
191 sections=section_weights(body_lines),
192 plain=plain,
193 )
194
195
196def section_weights(body_lines):
197 """按一级标题切分,返回各段字数占比。
198
199 自检器原先只查参数不查重心分布,而重心分布恰是区分
200 「单段独大型」与「均衡型」的关键——参数可以全部达标而文种写错。
201 """
202 secs, cur = [], ['导语', 0]
203 for l in body_lines:
204 if re.match(r'^\**[一二三四五六七八九十]+、', l):
205 secs.append(cur)
206 cur = [re.sub(r'^\**', '', l)[:16], 0]
207 cur[1] += len(l)
208 secs.append(cur)
209 tot = sum(n for _, n in secs) or 1
210 return [(name, n, round(100 * n / tot, 1)) for name, n in secs]
211
212
213def match_genre(a):
214 """算参数向量与各文种中位数的归一化距离,返回排序结果
215
216 quote_long 保留在 KEYS 里:它只定义在党建族一行,公文族各文种没有
217 这个字段而被跳过,因此实测长引语高会拉近党建族、拉远公文族。
218 """
219 KEYS = ['chars','sent','h1','h2','h3','yishi','dun','qz','yq','jy','pct',
220 'quote_long']
221 out = []
222 for g, r in REF.items():
223 d, cnt = 0.0, 0
224 for k in KEYS:
225 if k not in r: continue
226 lo, hi, mid = r[k]
227 scale = max(hi - lo, abs(mid) * 0.3, 1)
228 d += abs(a[k] - mid) / scale
229 cnt += 1
230 out.append((g, d / cnt))
231 return sorted(out, key=lambda x: x[1])
232
233
234def bar(val, lo, hi):
235 """在 p25-p75 区间中的位置示意"""
236 if hi <= lo:
237 return '│' if val == lo else ('←' if val < lo else '→')
238 span = hi - lo
239 pos = (val - lo) / span
240 if pos < -0.15: return '←低'
241 if pos > 1.15: return '高→'
242 slot = max(0, min(9, int(pos * 9)))
243 return '·' * slot + '●' + '·' * (9 - slot)
244
245
246def report(a, genre):
247 r, hard = REF[genre], HARD.get(genre, [])
248 print(f'\n{"="*76}')
249 print(f' 文体:{genre} 语料样本 n={r["n"]}')
250 print(f' 身份证参数:{ID_PARAM[genre]}')
251 print(f'{"="*76}\n')
252
253 # ① 硬冲突
254 fails = []
255 for key, ok_fn, msg, basis in hard:
256 if not ok_fn(a[key]):
257 fails.append((key, a[key], msg, basis))
258 print('【硬冲突检查】判文种识别错误,非风格差异')
259 print('-'*76)
260 if not fails:
261 print(f'✓ 通过({len(hard)} 项)')
262 else:
263 for key, val, msg, basis in fails:
264 print(f'✗ {msg}')
265 print(f' 实测 {key}={val} 依据:{basis}')
266
267 # 软提示
268 softs = [(k, a[k], m, b) for k, fn, m, b in SOFT.get(genre, []) if not fn(a[k])]
269 if softs:
270 print()
271 for key, val, msg, basis in softs:
272 print(f'⚠ {msg}')
273 print(f' 实测 {key}={val} {basis}')
274 print()
275
276 # ② 对照表
277 print('【参数对照】仅供参考,偏离不等于错误')
278 print('-'*76)
279 LABEL = {'chars':'字数','sent':'平均句长','h1':'一级标题','h2':'二级标题','h3':'三级标题',
280 'yishi':'"一是二是"','dun':'顿号密度‰','qz':'强制词','yq':'要求词','jy':'建议词',
281 'pct':'百分比','paras':'段落数','para_len':'段落长度','quote':'引号概念',
282 'quote_long':'长引语‰'}
283 print(f'{"指标":<12}{"你的":>8}{"中位":>8}{"常见区间":>12} 位置')
284 for k, label in LABEL.items():
285 if k not in r: continue
286 lo, hi, mid = r[k]
287 v = a[k]
288 flag = '' if lo <= v <= hi else ' ⚠偏离'
289 print(f'{label:<12}{v:>8}{mid:>8}{f"{lo}-{hi}":>12} {bar(v,lo,hi)}{flag}')
290
291 # ②b 标点修辞检查
292 dash_issues = []
293 if a['dash'] > 1:
294 dash_issues.append(f'正文破折号 {a["dash"]} 个(语料平均 0.2-0.9 个/篇,建议不超过 1 个)')
295 # 非引语冒号
296 non_quote_colons = []
297 for cm in re.finditer(r'([^\n]{0,12}):', a['plain']):
298 before = cm.group(1).strip()
299 if re.search(r'[一二三四五六七八九十]+、|([一二三四五六七八九十])|\d+[..]', before):
300 continue
301 if re.search(r'说|问|讲|提|指出|反映|回忆|告诉|表示|答', before):
302 continue
303 if re.search(r'人民政府|部门|单位|书记|镇长|同志|负责人', before):
304 continue
305 if '待补' in before or '待核' in before:
306 continue
307 non_quote_colons.append(cm.group(0)[:25])
308 if non_quote_colons:
309 dash_issues.append(f'非引语冒号 {len(non_quote_colons)} 处(冒号应只用于引语引入、主送机关、层次标题)')
310 # 元评论词(排除引号内——引语里的口语保留)
311 depunct_meta = re.sub(r'[“][^”]*[”]', '', a['plain'])
312 meta_words = re.findall(r'其实[是就]|说到底|归根到底|本质上', depunct_meta)
313 if meta_words:
314 dash_issues.append(f'元评论词 {len(meta_words)} 处({", ".join(set(meta_words))})')
315 if dash_issues:
316 print('\n【标点修辞检查】')
317 print('-'*76)
318 for di in dash_issues:
319 print(f'⚠ {di}')
320 elif a['dash'] <= 1:
321 pass # 不额外打印通过信息,保持报告简洁
322
323 # ③ 一级标题字数
324 if a['h1_titles']:
325 avg = sum(len(t) for t in a['h1_titles'])/len(a['h1_titles'])
326 biz = genre in ('工作意见','工作方案')
327 tgt = '4-12(业务类)' if biz else '14-24(分析类)'
328 print(f'\n一级标题平均 {avg:.1f} 字,目标 {tgt}')
329 for t in a['h1_titles'][:6]:
330 print(f' · {t}')
331
332 # ③b 重心分布:参数表测不到这一项,但它单独不足以判错(见 FOCUS 注释)
333 if genre in FOCUS and len(a['sections']) > 1:
334 lo, hi, mid, note = FOCUS[genre]
335 body = [s for s in a['sections'] if s[0] != '导语']
336 top = max(body, key=lambda s: s[2]) if body else None
337 print(f'\n【重心分布】仅供对照,偏离不等于错误')
338 print('-'*76)
339 for name, n, pct in a['sections']:
340 mark = ' ←最重' if top and name == top[0] else ''
341 print(f'{pct:>6.1f}% {n:>5}字 {name}{mark}')
342 if top:
343 print(f'最重一段 {top[2]}% 语料中位 {mid}%,常见 {lo}-{hi}%({note})')
344 if top[2] < lo or top[2] > hi:
345 print(f' 个体离散度大,此项区间外不作为错误;'
346 f'若同时有多项参数同向偏离,再考虑整体节奏问题。')
347
348 # ③c 引号书写提示:ASCII 直角引号无法配对,会令引号三项统计失真
349 if a['ascii_quote']:
350 print(f'\n⚠ 检出 {a["ascii_quote"]} 个 ASCII 直角引号(")。'
351 f'语料使用中文弯引号,混用会使引号概念与长引语统计失真')
352
353 # ④ 文种匹配度(仅在跨文体族误配、或差距显著时提示)
354 m = match_genre(a)
355 rank = [g for g, _ in m]
356 FAMILY = {'短经验材料': '党建族'}
357 fam_self = FAMILY.get(genre, '公文族')
358 fam_top = FAMILY.get(rank[0], '公文族')
359
360 if fam_self != fam_top:
361 # 跨文体族误配:两族在篇幅和一级标题上不重叠,这个信号强。
362 # 注:旧版记录的"网评识别准确率 94%"是含网评族时的三族数字,
363 # 网评族移除后未重测(语料原文已因版权移除),不再引用该数值。
364 print(f'\n【文体族检查】')
365 print('-'*76)
366 print(f'⚠ 你声明「{genre}」({fam_self}),但参数上更像「{rank[0]}」({fam_top})')
367 print(f' 两族参数互斥,判错族后所有参数都会偏。距离:'
368 + ' '.join(f'{g} {d:.2f}' for g, d in m[:3]))
369 elif genre in rank[3:]:
370 # 同族内排名靠后才提示——同族文种参数重叠严重,Top1 准确率仅 33-55%
371 print(f'\n【结构习惯提示】')
372 print('-'*76)
373 print(f'ⓘ 参数上「{genre}」排在第 {rank.index(genre)+1} 位,前三位是 '
374 + '、'.join(rank[:3]))
375 print(' 同族文种参数重叠大,此信号仅供参考,不代表文种判错。')
376
377 # ⑤ 避坑词
378 hits = [(w, why) for w, why in BAD_WORDS.items() if w in a['plain']]
379 if hits:
380 print(f'\n【避坑词】')
381 print('-'*76)
382 for w, why in hits:
383 print(f'⚠ "{w}" — {why}')
384
385 # ⑥ 力度词配额提示:改稿时最易踩的坑
386 if 'qz' in r and a['qz'] > r['qz'][1]:
387 print(f'\n⚠ 强制词超配额({a["qz"]} > {r["qz"][1]})。'
388 f'"要"属要求词、"必须/应当"属强制词,两者配额独立且相差一个量级,'
389 f'\n 改稿时把"要"整批替换成"必须"会直接顶破上限。')
390
391 print()
392 return len(fails)
393
394
395def main():
396 ap = argparse.ArgumentParser(add_help=False)
397 ap.add_argument('file', nargs='?')
398 ap.add_argument('--genre', '-g')
399 ap.add_argument('--match', action='store_true')
400 ap.add_argument('--list', action='store_true')
401 ap.add_argument('-h', '--help', action='store_true')
402 args = ap.parse_args()
403
404 if args.help or (not args.file and not args.list):
405 print(__doc__); sys.exit(0)
406 if args.list:
407 print('支持的文体:')
408 for k, v in ID_PARAM.items():
409 print(f' {k:<10} n={REF[k]["n"]:<4} {v}')
410 sys.exit(0)
411
412 try:
413 raw = Path(args.file).read_text(encoding='utf-8')
414 except FileNotFoundError:
415 print(f'找不到文件:{args.file}', file=sys.stderr); sys.exit(2)
416 except IsADirectoryError:
417 print(f'这是一个目录,不是文件:{args.file}', file=sys.stderr); sys.exit(2)
418 except UnicodeDecodeError:
419 print(f'无法按 UTF-8 读取(请确认是文本文件):{args.file}', file=sys.stderr); sys.exit(2)
420 except OSError as e:
421 print(f'读取失败:{args.file}({e.strerror})', file=sys.stderr); sys.exit(2)
422
423 a = analyze(raw)
424 if not a:
425 print('文件为空或无法解析', file=sys.stderr); sys.exit(2)
426
427 if args.match or not args.genre:
428 print(f'\n{args.file} 参数向量匹配结果:\n')
429 for i, (g, d) in enumerate(match_genre(a)):
430 print(f'{"★" if i==0 else " "} {g:<10} 距离 {d:.2f}')
431 print(f'\n实测:{a["chars"]}字 句长{a["sent"]} 一级{a["h1"]} 二级{a["h2"]} '
432 f'三级{a["h3"]} 一是{a["yishi"]} 顿号{a["dun"]}‰ 引号{a["quote"]} '
433 f'长引语{a["quote_long"]}‰')
434 body = [s for s in a['sections'] if s[0] != '导语']
435 if body:
436 top = max(body, key=lambda s: s[2])
437 print(f'重心:最重一段 {top[2]}%({top[0]})'
438 f' 各文种语料中位 33-46%\n')
439 else:
440 print()
441 sys.exit(0)
442
443 if args.genre not in REF:
444 print(f'未知文体:{args.genre}', file=sys.stderr)
445 print(f'可选:{"、".join(REF)}', file=sys.stderr)
446 if args.genre in NO_PARAM:
447 print(f'\n说明:{args.genre}属法定公文,本 skill 不为其设参数行——'
448 f'其正文结构由制度锁定,是固定填空而非写作技法,统计参数没有意义。',
449 file=sys.stderr)
450 print(f'`示例/` 里确有 {args.genre} 范文,但它们只做文体族校验与版式核对,不做参数验收。',
451 file=sys.stderr)
452 print(f'版式要素(发文字号、主送机关、成文日期、公开标识)请对照 '
453 f'`参考/法定公文样例/` 的真件;用 --match 可查它是否落在公文族内。', file=sys.stderr)
454 sys.exit(2)
455
456 fails = report(a, args.genre)
457 sys.exit(1 if fails else 0)
458
459
460if __name__ == '__main__':
461 main()

文件内容是平台检查时读出的文本,只供查看。平台不会运行包里的任何脚本或程序。