-
Notifications
You must be signed in to change notification settings - Fork 309
/
Copy pathmerge_by_toc.py
155 lines (131 loc) · 7.34 KB
/
merge_by_toc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env python3
# coding: utf8
from __future__ import print_function, unicode_literals
import re
import os
followups = []
in_toc = False
contents = []
# 定义正则表达式模式
hyper_link_pattern = re.compile(r'\[(.*?)\]\((.*?)(#.*?)?\)') # 匹配Markdown中的超链接
toc_line_pattern = re.compile(r'([\-\+]+)\s\[(.*?)\]\((.*?)(#.*?)?\)') # 匹配TOC中的行
image_link_pattern = re.compile(r'!\[(.*?)\]\((.*?)\)') # 匹配Markdown中的图片链接
level_pattern = re.compile(r'(\s*[\-\+]+)\s') # 匹配TOC中的层级
heading_patthern = re.compile(r'(^#+|\n#+)\s') # 匹配Markdown中的标题
copyable_snippet_pattern = re.compile(r'{{< copyable .* >}}') # 匹配可复制的代码段
entry_file = "TOC.md" # 入口文件
# 第1步,解析TOC文件
with open(entry_file) as fp: # 打开TOC文件
level = 0 # 初始化层级
current_level = "" # 初始化当前层级
for line in fp: # 逐行读取文件内容
if not in_toc and not line.startswith("<!-- "): # 判断是否进入TOC部分
in_toc = True # 设置标志,表示进入TOC部分
elif in_toc and not line.startswith('#') and line.strip(): # 处理TOC中的有效行
level_space_str = level_pattern.findall(line)[0][:-1] # 获取行的层级字符串
level = len(level_space_str) // 2 + 1 # 计算层级
matches = toc_line_pattern.findall(line) # 查找匹配的TOC行
if matches: # 如果有匹配的行
for match in matches: # 处理每一个匹配
fpath = match[2] # 获取文件路径
if fpath.endswith('.md'): # 如果是Markdown文件
fpath = fpath[1:] # 移除路径开头的斜杠
key = ('FILE', level, fpath) # 创建键
if key not in followups: # 如果键不在followups中
followups.append(key) # 添加键到followups
elif fpath.startswith('http'): # 如果是HTTP链接
followups.append(('TOC', level, line.strip()[2:])) # 添加HTTP链接到followups
else: # 如果没有匹配的行
name = line.strip().split(None, 1)[-1] # 获取目录项名称
key = ('TOC', level, name) # 创建键
if key not in followups: # 如果键不在followups中
followups.append(key) # 添加键到followups
else:
pass # 忽略其他行
# 第2步,获取文件标题
file_link_name = {} # 用于存储文件链接名称
title_pattern = re.compile(r'(^#+)\s.*') # 匹配标题
title_json_pattern = re.compile(r'"title":\s*"(.*?)"') # 匹配JSON中的title
for tp, lv, f in followups: # 遍历followups
if tp != 'FILE': # 如果类型不是文件,跳过
continue
try:
with open(f) as file: # 打开文件
lines = file.readlines() # 读取文件所有行
json_str = lines[2].strip() # 读取第三行的JSON字符串
print(f"json_str: {json_str}")
title_match = title_json_pattern.search(json_str) # 匹配JSON中的title
if title_match:
title = title_match.group(1) # 提取title
file_link_name[f] = title.lower().replace(' ', '-') # 存储标题链接名称
print(f"File: {f}, Title: {title}") # 打印文件名和标题
except Exception as e: # 捕获异常
print(e) # 打印异常
# 替换链接
def replace_link_wrap(chapter, name):
def replace_link(match):
full = match.group(0) # 获取完整的匹配
link_name = match.group(1) # 获取链接名称
link = match.group(2) # 获取链接地址
frag = match.group(3) # 获取链接片段
if link.startswith('http'): # 如果是HTTP链接
return full # 返回完整匹配
elif link.endswith('.md') or '.md#' in link: # 如果是Markdown文件链接
if not frag: # 如果没有片段
link = link[1:] # 去掉开头的斜杠
for fpath in file_link_name: # 遍历文件链接名称
if link == fpath: # 如果链接匹配
frag = '#' + file_link_name[fpath] # 添加片段
return '[%s](%s)' % (link_name, frag) # 返回替换后的链接
elif link.endswith('.png') or link.endswith('.jpeg') or link.endswith('.svg') or link.endswith('.gif') or link.endswith('.jpg'): # 如果是图片链接
img_link = re.sub(r'[\.\/]*images\/', 'static/images/', link, count=0, flags=0) # 替换图片路径
return '[%s](%s)' % (link_name, img_link) # 返回替换后的图片链接
else:
return full # 返回完整匹配
return hyper_link_pattern.sub(replace_link, chapter) # 替换章节中的链接
# 替换标题级别
def replace_heading_func(diff_level=0):
def replace_heading(match):
if diff_level == 0: # 如果没有级别差异
return match.group(0) # 返回原始匹配
else:
return '\n' + '#' * (match.group(0).count('#') + diff_level) + ' ' # 返回调整后的标题
return replace_heading # 返回替换函数
# 移除可复制代码段
def remove_copyable(match):
return '' # 返回空字符串,移除代码段
# 处理特殊字符的函数
def handle_special_characters(chapter):
chapter = chapter.replace("\\", "\\textbackslash{}") # 替换反斜杠
chapter = chapter.replace("~", "\\textasciitilde{}") # 替换波浪号
chapter = chapter.replace("^", "\\textasciicircum{}") # 替换脱字符
return chapter # 返回处理后的章节
# 第3步,合并文件
for type_, level, name in followups: # 遍历followups
if type_ == 'TOC': # 如果类型是TOC
contents.append("\n{} {}\n".format('#' * level, name)) # 添加目录项到内容
elif type_ == 'RAW': # 如果类型是RAW
contents.append(name) # 添加原始内容
elif type_ == 'FILE': # 如果类型是文件
try:
with open(name) as fp: # 打开文件
chapter = fp.read() # 读取文件内容
chapter = replace_link_wrap(chapter, name) # 替换链接
chapter = copyable_snippet_pattern.sub(remove_copyable, chapter) # 移除可复制代码段
# 处理特殊字符
chapter = handle_special_characters(chapter)
# 修正标题级别
diff_level = level - heading_patthern.findall(chapter)[0].count('#')
chapter = heading_patthern.sub(replace_heading_func(diff_level), chapter) # 替换标题级别
# 查找第二个---的位置
second_dash_pos = chapter.find('---', chapter.find('---') + 1)
if second_dash_pos != -1:
# 在第二个---之后插入一级标题
chapter = chapter[:second_dash_pos + 3] + f"\n\n# {file_link_name[name]}\n\n" + chapter[second_dash_pos + 3:]
contents.append(chapter) # 添加章节到内容
except Exception as e: # 捕获异常
print(e) # 打印异常
# 第4步,生成最终文档
target_doc_file = 'doc.md' # 目标文档文件名
with open(target_doc_file, 'w') as fp: # 打开目标文档文件
fp.write('\n'.join(contents)) # 写入内容到文件