1- #!/usr/bin/env python
1+ # update.py
2+ #!/usr/bin/env python3
23
34import os
45from urllib import parse
56
6- HEADER = """
7- # 🎯 백준, 프로그래머스, SWEA 문제 풀이 목록
7+ README_PATH = "README.md"
8+ START_MARKER = "<!-- AA-README-START -->"
9+ END_MARKER = "<!-- AA-README-END -->"
10+
11+ GENERATED_HEADER = """
12+ ## 📚 Problem Solving
813"""
914
10- # 백준 등급 이모지 매핑 (예시)
1115BOJ_TIER_ORDER = {
1216 "Bronze" : "🥉 Bronze" ,
1317 "Silver" : "🥈 Silver" ,
1721 "Ruby" : "❤️ Ruby"
1822}
1923
20- # 프로그래머스 레벨 이모지 매핑 (예시)
2124PROGRAMMERS_LEVEL = {
2225 "0" : "🍼 Lv.0" ,
2326 "1" : "🐣 Lv.1" ,
2730 "5" : "🦅 Lv.5"
2831}
2932
30- # SWEA 단계 이모지 매핑 (예시)
31- def swea_label (name ) :
33+
34+ def swea_label (name : str ) -> str :
3235 return f"⭐ { name .upper ()} "
3336
37+
3438def parse_problem_folder (folder_name : str ) -> str :
35- """
36- '1000. A+B' 같은 폴더 이름을 '1000 - A+B' 로 변환.
37- 폴더명에 '.'이 없으면 그대로 반환.
38- """
3939 if "." in folder_name :
4040 parts = folder_name .split ("." , 1 )
4141 prob_num = parts [0 ].strip ()
4242 prob_title = parts [1 ].strip ()
4343 return f"{ prob_num } - { prob_title } "
44- else :
45- return folder_name
46-
47- def extract_problem_number (folder_name : str ) -> int :
48- """
49- 폴더 이름에서 문제 번호를 추출합니다.
50- 예: "1152. A+B" -> 1152
51- 폴더 이름에 '.'가 없으면 정렬 시 뒤로 밀리도록 큰 값을 반환.
52- """
44+ return folder_name
45+
46+
47+ def extract_problem_number (folder_name : str ):
5348 if "." in folder_name :
5449 try :
55- num_part = folder_name .split ("." )[0 ].strip ()
56- return int (num_part )
50+ return int (folder_name .split ("." )[0 ].strip ())
5751 except ValueError :
5852 return float ("inf" )
59- else :
60- return float ("inf" )
53+ return float ("inf" )
54+
55+
56+ def build_generated_content () -> str :
57+ content = GENERATED_HEADER + "\n "
6158
62- def main ():
63- content = HEADER + "\n "
64-
65- # 메인 카테고리 이름들
6659 main_categories = ["백준" , "프로그래머스" , "SWEA" ]
67- # 데이터 구조:
68- # data[(메인카테고리, 서브카테고리)] = { 문제폴더이름: [파일경로, ...] }
6960 data = {}
70-
61+
7162 for root , dirs , files in os .walk ("." ):
72- # .git, .github, images 폴더는 건너뛰기
7363 dirs [:] = [d for d in dirs if d not in (".git" , ".github" , "images" )]
74- if root == "." : # 루트 디렉토리는 건너뜁니다.
64+
65+ if root == "." :
7566 continue
76-
77- # 경로(root)에서 메인 카테고리가 어느 것에 속하는지 체크
67+
7868 main_cat = None
7969 for cat in main_categories :
8070 if os .sep + cat + os .sep in root or root .endswith (os .sep + cat ) or root == "./" + cat :
8171 main_cat = cat
8272 break
73+
8374 if main_cat is None :
8475 continue
85-
86- # 메인 카테고리 바로 아래 폴더(또는 그 아래 하위 경로)를 서브 카테고리(sub_cat)로 간주합니다.
76+
8777 main_path = os .path .join ("." , main_cat )
88- rel_path = os .path .relpath (root , main_path ) # 예: 'Bronze/1000. A+B' 등
78+ rel_path = os .path .relpath (root , main_path )
8979 parts = rel_path .split (os .sep )
90- sub_cat = parts [0 ] # 예: Bronze 또는 "." (파일이 바로 메인 폴더에 있을 때)
91-
92- # 문제 폴더가 있다면 (예: "1000. A+B")
80+ sub_cat = parts [0 ]
81+
9382 problem_folder = None
9483 if len (parts ) > 1 :
9584 problem_folder = parts [1 ]
96-
97- # data 초기화
85+
9886 if (main_cat , sub_cat ) not in data :
9987 data [(main_cat , sub_cat )] = {}
100-
88+
10189 if problem_folder is not None :
10290 if problem_folder not in data [(main_cat , sub_cat )]:
10391 data [(main_cat , sub_cat )][problem_folder ] = []
104-
92+
10593 for file in files :
106- if file .lower () == "readme.md" : # 문제 설명 파일 제외
94+ if file .lower () == "readme.md" :
10795 continue
10896 full_path = os .path .join (root , file )
10997 data [(main_cat , sub_cat )][problem_folder ].append (full_path )
110- else :
111- # sub_cat 자체가 문제 폴더인 경우(메인 카테고리 폴더에 바로 파일이 있는 경우)
112- pass
113-
114- # data의 내용을 바탕으로 content 구성 - 각 서브 카테고리(레벨)별로 하나의 표 생성
98+
11599 for main_cat in main_categories :
116- # 해당 메인 카테고리에 해당하는 (main_cat, sub_cat) 키 목록
117100 keys = [(k , v ) for k , v in data .items () if k [0 ] == main_cat ]
118101 if not keys :
119102 continue
120-
121- # 메인 카테고리 헤더
103+
122104 content += "---\n "
123105 content += f"## 📚 { main_cat } \n "
124-
125- # 서브 카테고리(예: Bronze, Silver 등) 정렬
106+
126107 if main_cat == "백준" :
127108 order = ["Bronze" , "Silver" , "Gold" , "Platinum" , "Diamond" , "Ruby" ]
128- keys_sorted = sorted (keys , key = lambda item : order .index (item [0 ][1 ]) if item [0 ][1 ] in order else 999 )
109+ keys_sorted = sorted (
110+ keys ,
111+ key = lambda item : order .index (item [0 ][1 ]) if item [0 ][1 ] in order else 999
112+ )
129113 else :
130114 keys_sorted = sorted (keys , key = lambda x : x [0 ][1 ])
131-
115+
132116 for (mc , sub_cat ), problem_map in keys_sorted :
133117 if sub_cat == "." :
134118 continue
135-
119+
136120 if mc == "백준" :
137121 tier_title = BOJ_TIER_ORDER .get (sub_cat , f"✅ { sub_cat } " )
138122 elif mc == "프로그래머스" :
@@ -145,17 +129,42 @@ def main():
145129 content += f"### { tier_title } \n "
146130 content += "| 문제 | 링크 |\n "
147131 content += "| ----- | ---- |\n "
148-
149- # 문제 폴더를 문제 번호 기준(숫자)으로 정렬합니다.
150- for pfolder , file_list in sorted (problem_map .items (), key = lambda item : extract_problem_number (item [0 ])):
132+
133+ for pfolder , _ in sorted (problem_map .items (), key = lambda item : extract_problem_number (item [0 ])):
151134 parsed_name = parse_problem_folder (pfolder )
152135 folder_path = os .path .join ("." , mc , sub_cat , pfolder )
153136 content += f"| { parsed_name } | [링크]({ parse .quote (folder_path )} ) |\n "
154-
137+
155138 content += "\n "
156-
157- with open ("README.md" , "w" , encoding = "utf-8" ) as fd :
158- fd .write (content )
139+
140+ return content .strip () + "\n "
141+
142+
143+ def update_readme ():
144+ generated = build_generated_content ()
145+
146+ if os .path .exists (README_PATH ):
147+ with open (README_PATH , "r" , encoding = "utf-8" ) as f :
148+ readme = f .read ()
149+ else :
150+ readme = ""
151+
152+ block = f"{ START_MARKER } \n { generated } { END_MARKER } "
153+
154+ if START_MARKER in readme and END_MARKER in readme :
155+ start = readme .index (START_MARKER )
156+ end = readme .index (END_MARKER ) + len (END_MARKER )
157+ updated = readme [:start ] + block + readme [end :]
158+ else :
159+ prefix = readme .strip ()
160+ if prefix :
161+ updated = prefix + "\n \n ---\n \n " + block + "\n "
162+ else :
163+ updated = block + "\n "
164+
165+ with open (README_PATH , "w" , encoding = "utf-8" ) as f :
166+ f .write (updated )
167+
159168
160169if __name__ == "__main__" :
161- main ()
170+ update_readme ()
0 commit comments