-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextract_comments.py
More file actions
173 lines (140 loc) · 5.3 KB
/
Copy pathextract_comments.py
File metadata and controls
173 lines (140 loc) · 5.3 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
"""
提取项目中所有 Python 文件的注释和文档字符串,生成结构化 txt 文件。
输出格式:
FILE: <文件路径>
LINE: <行号> | TYPE: <inline|docstring> | LANG: <en|zh|mixed>
<注释内容(可能多行)>
END
---
"""
import os
import re
import ast
import sys
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
OUTPUT_FILE = os.path.join(PROJECT_ROOT, "comments_extracted.txt")
# 跳过的目录
SKIP_DIRS = {"__pycache__", ".git", ".idea", "venv", "env", "node_modules"}
def has_chinese(text: str) -> bool:
return bool(re.search(r'[一-鿿]', text))
def has_english_letter(text: str) -> bool:
return bool(re.search(r'[a-zA-Z]{2,}', text))
def classify_lang(text: str) -> str:
"""判断文本语言:en / zh / mixed"""
zh = has_chinese(text)
en = has_english_letter(text)
if zh and en:
return "mixed"
if zh:
return "zh"
if en:
return "en"
return "other"
def extract_comments_from_file(filepath: str) -> list[dict]:
"""从单个 Python 文件中提取行内注释和文档字符串。"""
results = []
try:
with open(filepath, "r", encoding="utf-8") as f:
source = f.read()
except Exception as e:
print(f" [SKIP] {filepath}: {e}", file=sys.stderr)
return results
lines = source.splitlines(keepends=True)
rel_path = os.path.relpath(filepath, PROJECT_ROOT)
# --- 1. 提取行内注释 (# ...) ---
for i, line in enumerate(lines, start=1):
stripped = line.strip()
# 跳过 shebang 和 encoding 声明
if stripped.startswith("#!") or stripped.startswith("# -*-") or stripped.startswith("# coding"):
continue
# 找到 # 但不在字符串中(简单启发式)
# 使用正则:匹配行尾的 # 注释(排除 URL 中的 #)
m = re.search(r'(?<!["\'])# (.+)', line)
if m:
comment_text = m.group(1).strip()
if comment_text:
results.append({
"file": rel_path,
"line": i,
"type": "inline",
"lang": classify_lang(comment_text),
"content": comment_text,
})
# --- 2. 提取文档字符串 (""" ... """) ---
try:
tree = ast.parse(source)
except SyntaxError:
return results
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Module)):
# 获取 docstring
if (node.body and isinstance(node.body[0], ast.Expr)
and isinstance(node.body[0].value, ast.Constant)
and isinstance(node.body[0].value.value, str)):
expr_node = node.body[0]
docstring = expr_node.value.value
docstring = docstring.strip()
if not docstring:
continue
# 判断是否为纯英文需要翻译
lang = classify_lang(docstring)
# 计算 docstring 在源码中的起始行
start_line = expr_node.lineno
# 估算结束行
end_line = start_line + docstring.count('\n')
results.append({
"file": rel_path,
"line": start_line,
"end_line": end_line,
"type": "docstring",
"lang": lang,
"content": docstring,
})
return results
def main():
all_comments = []
py_files = []
for root, dirs, files in os.walk(PROJECT_ROOT):
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
for fname in files:
if fname.endswith(".py"):
py_files.append(os.path.join(root, fname))
py_files.sort()
print(f"扫描到 {len(py_files)} 个 Python 文件...")
for fpath in py_files:
comments = extract_comments_from_file(fpath)
if comments:
all_comments.extend(comments)
# 按文件分组写入
en_count = 0
zh_count = 0
mixed_count = 0
with open(OUTPUT_FILE, "w", encoding="utf-8") as out:
current_file = None
for c in all_comments:
if c["file"] != current_file:
if current_file is not None:
out.write("---\n")
current_file = c["file"]
out.write(f"FILE: {current_file}\n")
out.write(f"LINE: {c['line']} | TYPE: {c['type']} | LANG: {c['lang']}\n")
if c["type"] == "docstring":
out.write(f"END_LINE: {c.get('end_line', c['line'])}\n")
out.write(f"{c['content']}\n")
out.write("END\n")
if c["lang"] == "en":
en_count += 1
elif c["lang"] == "zh":
zh_count += 1
elif c["lang"] == "mixed":
mixed_count += 1
if current_file is not None:
out.write("---\n")
print(f"\n提取完成!输出文件: {OUTPUT_FILE}")
print(f" 总注释数: {len(all_comments)}")
print(f" 英文 (en): {en_count}")
print(f" 中文 (zh): {zh_count}")
print(f" 混合 (mixed): {mixed_count}")
print(f" 其他 (other): {len(all_comments) - en_count - zh_count - mixed_count}")
if __name__ == "__main__":
main()