Skip to content

feat: initialize mkdocs config #2231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs-en/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# LeetCode EN Wiki
10 changes: 10 additions & 0 deletions docs-en/javascripts/katex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
document$.subscribe(({ body }) => {
renderMathInElement(body, {
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '$', right: '$', display: false },
{ left: '\\(', right: '\\)', display: false },
{ left: '\\[', right: '\\]', display: true },
],
});
});
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# LeetCode Wiki
10 changes: 10 additions & 0 deletions docs/javascripts/katex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
document$.subscribe(({ body }) => {
renderMathInElement(body, {
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '$', right: '$', display: false },
{ left: '\\(', right: '\\)', display: false },
{ left: '\\[', right: '\\]', display: true },
],
});
});
337 changes: 168 additions & 169 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,42 @@
from itertools import pairwise
import os
import re
from collections import defaultdict

# 获取 leetcode 题目,结构如下:
"""
- solution
- 0000-0099
- 0001.Two Sum/README.md
- 0002.Add Two Numbers/README.md
- 0100-0199
- 0100.Same Tree/README.md
- 0101.Symmetric Tree/README.md
- lcof
- 面试题03. 数组中重复的数字/README.md
- 面试题04. 二维数组中的查找/README.md
- lcof2
- 剑指 Offer II 001. 整数除法/README.md
- 剑指 Offer II 002. 二进制加法/README.md
- lcci
- 01.01.Is Unique/README.md
- 01.02.Check Permutation/README.md
"""

# 生成 leetcode 题目导航
"""
nav:
- LeetCode:
- 1. 两数之和: lc/1.md
- 2. 两数相加: lc/2.md
- 100. 相同的树: lc/100.md
- 剑指 Offer(第 2 版):
- 面试题3. 数组中重复的数字: lcof/3.md
- 剑指 Offer(专项突击版):
- 1. 整数除法: lcof2/1.md
- 程序员面试金典(第 6 版):
- 面试题 01.01. 判定字符是否唯一: lcci/1.1.md
"""

sorted_suffixes = [
"py",
"java",
"cpp",
"go",
"ts",
"rs",
"js",
"cs",
"php",
"c",
"scala",
"swift",
"rb",
"kt",
"nim",
"sql",
]
code_dict = {
"py": ("Python3", "python"),
"java": ("Java", "java"),
Expand All @@ -39,162 +56,144 @@
"sql": ("MySQL", "sql"),
}

mapping = {lang: name for name, lang in code_dict.values()}

# 抽取代码块
def extract_code():
paths = []
for root, _, files in os.walk(os.getcwd()):
for file in files:
path = root + "/" + file
if "node_modules" in path or "__pycache__" in path or ".git" in path:
continue
if root == "D:\github-repo\leetcode":
continue
if path.endswith("README.md"):
paths.append(path)
for path in paths:
with open(path, "r", encoding="utf-8") as f:
content = f.read()
mark = "<!-- tabs:start -->"
i = content.find(mark)
if i == -1:
continue
content = content[i + len(mark) :]
for suffix, (_, suf) in code_dict.items():
res = re.findall(f"```{suf}\n(.*?)```", content, re.S)
if not res:
continue
cnt = 1
for block in res:
if not block or not block.strip():
continue
if suf in ["java", "cpp", "go", "c"]:
block = block.rstrip()
name = f"{path[:path.rfind('/')]}/Solution{'' if cnt == 1 else str(cnt)}.{suffix}"
with open(name, "w", encoding="utf-8") as f:
f.write(block)
cnt += 1


def parse_content(content, start, end, titles):
i = content.find(start)
if i == -1:
return []
j = content.find(end)
if j == -1:
return []
content = content[i + len(start) : j]
blocks = []
idx = [content.find(title) for title in titles]
for l, r in pairwise(idx):
block = content[l:r].strip()
if not block:
continue
line = block.split("\n")[0]
method_name = line[2:-2]
block = block.replace(line, f"### {method_name}")
blocks.append(block)
return blocks


def extract_solution_paragraph():
with open("mkdocs.yml", "r", encoding="utf-8") as f:
config = f.read()

with open("mkdocs-en.yml", "r", encoding="utf-8") as f:
en_config = f.read()


def get_paths(dirs: str, m: int):
dirs = 'main' + os.sep + dirs
paths = []
for root, _, files in os.walk(os.getcwd()):
for root, _, files in os.walk(dirs):
for file in files:
path = root + "/" + file
if "node_modules" in path or "__pycache__" in path or ".git" in path:
continue
if root == "D:\github-repo\leetcode":
continue
if path.endswith("README.md") or path.endswith("README_EN.md"):
paths.append(path)
for path in paths:
with open(path, "r", encoding="utf-8") as f:
content = f.read()
file_name = os.path.join(root, file)
if file.endswith(".md") and len(file_name.split(os.sep)) == m:
paths.append(file_name)
return paths

is_cn = path.endswith("README.md")
if is_cn:
blocks = parse_content(
content,
"## 解法",
"<!-- tabs:start -->",
["**方法一:", "**方法二:", "**方法三:", "**方法四:"],
)
else:
print(path)
blocks = parse_content(
content,
"## Solutions",
"<!-- tabs:start -->",
["**Solution 1:", "**Solution 2:", "**Solution 3:", "**Solution 4:"],
)

prefix = path[: path.rfind("/")]
tab_start = "<!-- tabs:start -->"
tab_end = "<!-- tabs:end -->"
for i in range(1, 5):
codes = []
for suf in sorted_suffixes:
seq = '' if i == 1 else str(i)
file_name = f"{prefix}/Solution{seq}.{suf}"
try:
with open(file_name, "r", encoding="utf-8") as f:
code = f.read().strip()
code = '```' + code_dict[suf][1] + '\n' + code + '\n```'
codes.append(code)
except:
continue
if codes:
if i > len(blocks):
seq_dict = {1: '一', 2: '二', 3: '三', 4: '四'}
title = f"### 方法{seq_dict[i]}" if is_cn else f"### Solution {i}"
block = (
title
+ '\n\n'
+ tab_start
+ '\n\n'
+ '\n\n'.join(codes)
+ '\n\n'
+ tab_end
)
blocks.append(block)
else:
block = (
blocks[i - 1]
+ '\n\n'
+ tab_start
+ '\n\n'
+ '\n\n'.join(codes)
+ '\n\n'
+ tab_end
)
blocks[i - 1] = block
is_problem = (
content.find("## 解法") != -1
if is_cn
else content.find("## Solutions") != -1
and content.find("## Description") != -1
)
start = '## 解法' if is_cn else '## Solutions'
end = '<!-- end -->'
if blocks:
content = (
content[: content.find(start)]
+ start
+ '\n\n'
+ '\n\n'.join(blocks)
+ '\n\n'
+ end
dirs_mapping = {
"solution": ("lc", 5),
"lcof": ("lcof", 4),
"lcof2": ("lcof2", 4),
"lcci": ("lcci", 4),
"lcp": ("lcp", 4),
"lcs": ("lcs", 4),
}

dirs = ["solution", "lcof", "lcof2", "lcci", "lcp", "lcs"]

"""
nav:
- LeetCode
- 1. 两数之和: lc/1.md
- 2. 两数相加: lc/2.md
"""

navdata_cn = defaultdict(list)
navdata_en = defaultdict(list)

for dir in dirs:
target_dir, m = dirs_mapping[dir]
for p in sorted(get_paths(dir, m)):
with open(p, "r", encoding="utf-8") as f:
content = f.read()
title = content[content.find("[") + 1 : content.find("]")]
dot = title.find(".") if dir != "lcci" else title.rfind(".")
num = (
title[:dot]
.replace("面试题", "")
.replace("剑指 Offer II", "")
.replace("LCP", "")
.replace("LCS", "")
.strip(" ")
.lstrip("0")
)
with open(path, "w", encoding="utf-8") as f:
f.write(content)
elif is_problem:
start = '## 解法' if is_cn else '## Solutions'
content = content[: content.find(start)] + start + '\n\n' + end
with open(path, "w", encoding="utf-8") as f:
name = (
title[dot + 1 :]
.replace("面试题", "")
.replace("剑指 Offer II", "")
.replace("LCP", "")
.replace("LCS", "")
.strip(" ")
.lstrip("0")
)
if num.endswith("- III"):
num = num[:-5] + ".3"
elif num.endswith("- II"):
num = num[:-4] + ".2"
elif num.endswith("- I"):
num = num[:-3] + ".1"
num = ".".join([x.strip(" ").lstrip("0") for x in num.split(".")])
is_en = "README_EN" in p
if is_en:
navdata_en[dir].append(f" - {num}. {name}: {target_dir}/{num}.md")
else:
navdata_cn[dir].append(f" - {num}. {name}: {target_dir}/{num}.md")
# 修改代码块
while True:
start = "<!-- tabs:start -->"
end = "<!-- tabs:end -->"
i = content.find(start)
j = content.find(end)
if i == -1 or j == -1:
break
j = content.find(end)
codes = content[i + len(start) : j].strip()
res = re.findall(r"```(.+?)\n(.+?)\n```", codes, re.DOTALL)
result = []
if res:
for lang, code in res:
name = mapping.get(lang)
# 需要将 code 缩进 4 个空格
code = code.replace("\n", "\n ")
code_snippet = (
f'=== "{name}"\n\n ```{lang}\n {code}\n ```\n'
)
result.append(code_snippet)
content = content[:i] + "\n".join(result) + content[j + len(end) :]
docs_dir = ("docs-en" if is_en else "docs") + os.sep + target_dir
if not os.path.exists(docs_dir):
os.makedirs(docs_dir)
new_path = os.path.join(docs_dir, f"{num}.md")
with open(new_path, "w", encoding="utf-8") as f:
f.write(content)

navdata_en[dir].sort(key=lambda x: int(x.split(".")[0].split(" ")[-1]))
navdata_cn[dir].sort(key=lambda x: int(x.split(".")[0].split(" ")[-1]))

if "nav:" in config:
config = config[: config.find("nav:")]
if "nav:" in en_config:
en_config = en_config[: en_config.find("nav:")]

config += "\nnav:\n"
en_config += "\nnav:\n"
config += " - LeetCode:\n"
en_config += " - LeetCode:\n"
config += "\n".join(navdata_cn["solution"])
en_config += "\n".join(navdata_en["solution"])
config += "\n"
en_config += "\n"
config += " - 剑指 Offer(第 2 版):\n"
config += "\n".join(navdata_cn["lcof"])
config += "\n"
config += " - 剑指 Offer(专项突击版):\n"
config += "\n".join(navdata_cn["lcof2"])
config += "\n"
config += " - 程序员面试金典(第 6 版):\n"
config += "\n".join(navdata_cn["lcci"])
config += "\n"
en_config += " - Cracking the Coding Interview, 6th Edition:\n"
en_config += "\n".join(navdata_en["lcci"])
en_config += "\n"

with open("mkdocs.yml", "w", encoding="utf-8") as f:
f.write(config)

if __name__ == "__main__":
extract_code()
extract_solution_paragraph()
with open("mkdocs-en.yml", "w", encoding="utf-8") as f:
f.write(en_config)
Loading