修正: deepseek 笔记 96 处块级公式改为多行写法(适配 SilverBullet 行首锚点), 索引脚本同步 _abstract 命名
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
"""Audit / convert single-line $$...$$ math blocks for SilverBullet compatibility.
|
||||
|
||||
SilverBullet's Math library defines block math with the line-anchored marker
|
||||
regex ^\\$\\$$ for BOTH start and end, so `$$...$$` written on one line never
|
||||
closes and is rendered as raw text.
|
||||
|
||||
Usage:
|
||||
python math_fix.py audit <base_dir>
|
||||
python math_fix.py convert <base_dir> [--apply]
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
CMD = sys.argv[1]
|
||||
BASE = sys.argv[2] if len(sys.argv) > 2 else '.'
|
||||
APPLY = '--apply' in sys.argv
|
||||
|
||||
LINE_RE = re.compile(r'^\$\$(.+)\$\$$')
|
||||
|
||||
|
||||
def notes():
|
||||
for root, dirs, files in os.walk(BASE):
|
||||
if any(x in root for x in ['_scripts', '_text', '_digest', '.git']):
|
||||
continue
|
||||
for fn in sorted(files):
|
||||
if fn.endswith('.md') and fn != 'README.md':
|
||||
yield os.path.join(root, fn)
|
||||
|
||||
|
||||
def walk_lines(path):
|
||||
"""Yield (index, line, in_fence)."""
|
||||
fence = False
|
||||
lines = open(path, encoding='utf-8').read().split('\n')
|
||||
for i, line in enumerate(lines):
|
||||
if line.lstrip().startswith('```'):
|
||||
yield i, line, fence
|
||||
fence = not fence
|
||||
continue
|
||||
yield i, line, fence
|
||||
|
||||
|
||||
def audit():
|
||||
total = indented = multi = in_fence = trailing = 0
|
||||
samples = []
|
||||
for p in notes():
|
||||
for i, line, fence in walk_lines(p):
|
||||
s = line.strip()
|
||||
if not s.startswith('$$') or s.count('$$') < 2:
|
||||
continue
|
||||
total += 1
|
||||
if fence:
|
||||
in_fence += 1
|
||||
samples.append(('FENCE', p, i, s[:90]))
|
||||
if line != line.lstrip():
|
||||
indented += 1
|
||||
samples.append(('INDENT', p, i, s[:90]))
|
||||
if s.count('$$') > 2:
|
||||
multi += 1
|
||||
samples.append(('MULTI', p, i, s[:90]))
|
||||
if not s.endswith('$$'):
|
||||
trailing += 1
|
||||
samples.append(('TAILTEXT', p, i, s[-80:]))
|
||||
print('单行 $$ 块总数 :', total)
|
||||
print(' 其中在代码块内 :', in_fence)
|
||||
print(' 其中带前导缩进 :', indented)
|
||||
print(' 其中一行含 >2 个 $$ :', multi)
|
||||
print(' 其中不以 $$ 结尾 :', trailing)
|
||||
for kind, p, i, s in samples[:20]:
|
||||
print(' [%s] %s:%d %s' % (kind, os.path.relpath(p, BASE), i + 1, s))
|
||||
|
||||
|
||||
def convert():
|
||||
files_changed = 0
|
||||
blocks_changed = 0
|
||||
skipped = []
|
||||
for p in notes():
|
||||
lines = open(p, encoding='utf-8').read().split('\n')
|
||||
out = []
|
||||
fence = False
|
||||
n = 0
|
||||
for line in lines:
|
||||
if line.lstrip().startswith('```'):
|
||||
fence = not fence
|
||||
out.append(line)
|
||||
continue
|
||||
m = LINE_RE.match(line)
|
||||
if m and not fence:
|
||||
body = m.group(1).strip()
|
||||
if '$$' in body:
|
||||
skipped.append((os.path.relpath(p, BASE), line[:90]))
|
||||
out.append(line)
|
||||
continue
|
||||
out.append('$$')
|
||||
out.append(body)
|
||||
out.append('$$')
|
||||
n += 1
|
||||
continue
|
||||
out.append(line)
|
||||
if n:
|
||||
files_changed += 1
|
||||
blocks_changed += n
|
||||
print('%3d 处 %s' % (n, os.path.relpath(p, BASE)))
|
||||
if APPLY:
|
||||
with open(p, 'w', encoding='utf-8', newline='\n') as f:
|
||||
f.write('\n'.join(out))
|
||||
print()
|
||||
print('文件数: %d 转换块数: %d' % (files_changed, blocks_changed))
|
||||
if skipped:
|
||||
print('跳过(正文含 $$,需人工确认):')
|
||||
for s in skipped:
|
||||
print(' ', s)
|
||||
print('模式:', '已写入' if APPLY else '预演(未写入,加 --apply 才落盘)')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if CMD == 'audit':
|
||||
audit()
|
||||
elif CMD == 'convert':
|
||||
convert()
|
||||
else:
|
||||
raise SystemExit('unknown command: ' + CMD)
|
||||
Reference in New Issue
Block a user