1 # system module 2 import os 3 import re 4 import tkinter 5 import tkinter.messagebox 6 import tkinter.filedialog 7 import tkinter.ttk 8 import sys 9 import logging 10 11 logger = logging.getLogger(__name__) 12 13 def create_logger(filename="log.txt", level=logging.INFO, console_swtich = True): 14 # 獲取logger實例,如果參數為空則返回root logger 15 # logger = logging.getLogger(__name__) 16 17 # 創建日志輸出格式 18 formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d][%(funcName)s] - %(levelname)s - %(message)s") 19 20 # 指定輸出的文件路徑 21 file_handler = logging.FileHandler(filename) 22 # 設置文件處理器格式 23 file_handler.setFormatter(formatter) 24 25 # 為logger添加的日志處理器 26 logger.addHandler(file_handler) 27 28 # 控制台日志 29 if console_swtich: 30 console_handler = logging.StreamHandler(sys.stdout) 31 console_handler.formatter = formatter 32 logger.addHandler(console_handler) 33 34 # 指定日志的最低輸出級別,默認為warn級別 35 logger.setLevel(level) 36 37 return logger 38 39 class modify_string(): 40 #界面布局方法 41 def __init__(self): 42 #創建界面,並且保存到成員屬性中 43 self.root = tkinter.Tk() 44 self.root.minsize(400, 170) 45 self.root.resizable(0, 0) 46 self.root.title("批量修改字符串") 47 48 #文件夾路徑 49 self.path = tkinter.StringVar() 50 self.path.set("") 51 52 #選項 53 self.folder_name = tkinter.IntVar() 54 self.file_name = tkinter.IntVar() 55 self.file_content = tkinter.IntVar() 56 57 #字符串 58 self.string_old = tkinter.StringVar() 59 self.string_new = tkinter.StringVar() 60 61 #進度 62 self.progress = tkinter.StringVar() 63 self.progress.set("開始修改") 64 65 #界面布局 66 self.menus() 67 self.layout() 68 self.root.mainloop() 69 70 def menus(self): 71 #添加菜單 72 73 #創建總菜單 74 allmenu = tkinter.Menu(self.root) 75 76 # 添加子菜單1 77 debugmenu = tkinter.Menu(allmenu, tearoff=0) 78 debugmenu.add_command(label="日志", 79 command=self.log) 80 81 allmenu.add_cascade(label="調試", 82 menu=debugmenu) 83 84 # 添加子菜單2 85 helpmenu = tkinter.Menu(allmenu, tearoff=0) 86 87 # 添加選項卡 88 helpmenu.add_command(label='規則', 89 command=self.rule) 90 helpmenu.add_command(label='版本說明', 91 command=self.release_note) 92 helpmenu.add_command(label='關於', 93 command=self.about) 94 95 allmenu.add_cascade(label='幫助', 96 menu=helpmenu) 97 98 tkinter.ttk.Separator(self.root, orient="horizontal").pack(fill="x", padx=0) 99 100 101 self.root.config(menu=allmenu) 102 103 def layout(self): 104 #布局 105 #文件夾路徑 106 path_description = tkinter.Label(self.root, 107 font=("宋體", 10), 108 fg="blue", 109 anchor="w", 110 text="文件夾路徑") 111 path_description.place(x=5, y=10, width=70, height=20) 112 113 path_show = tkinter.Label(self.root, 114 bd=3, 115 bg='white', 116 font=("宋體", 10), 117 anchor="e", 118 textvariable=self.path) 119 path_show.place(x=80, y=10, width=250, height=20) 120 121 button_path = tkinter.Button(self.root, 122 text='選擇', 123 command=self.select_path) 124 button_path.place(x=335, y=10, width=60, height=20) 125 126 # 選項 127 option = tkinter.Label(self.root, 128 font=("宋體", 10), 129 fg="blue", 130 anchor="w", 131 text="修改選項") 132 option.place(x=5, y=40, width=70, height=20) 133 134 folder_select =tkinter.Checkbutton(self.root, 135 text="文件夾名稱", 136 anchor="w", 137 variable=self.folder_name) 138 folder_select.place(x=80, y=40, width=100, height=20) 139 140 folder_select = tkinter.Checkbutton(self.root, 141 text="文件名稱", 142 anchor="w", 143 variable=self.file_name) 144 folder_select.place(x=185, y=40, width=100, height=20) 145 146 folder_select = tkinter.Checkbutton(self.root, 147 text="文件內容", 148 anchor="w", 149 variable=self.file_content) 150 folder_select.place(x=290, y=40, width=100, height=20) 151 152 #字符串 153 tkinter.Label(self.root, 154 font=("宋體", 10), 155 fg="blue", 156 anchor="w", 157 text="原字符串").place(x=5, y=70, width=70, height=20) 158 source_text = tkinter.Entry(self.root, 159 textvariable=self.string_old) 160 source_text.place(x=80, y=70, width=310, height=20) 161 162 tkinter.Label(self.root, 163 font=("宋體", 10), 164 fg="blue", 165 anchor="w", 166 text="新字符串").place(x=5, y=100, width=70, height=20) 167 source_text = tkinter.Entry(self.root, 168 textvariable=self.string_new) 169 source_text.place(x=80, y=100, width=310, height=20) 170 171 # 開始修改 172 button_start = tkinter.Button(self.root, 173 font=("宋體", 12), 174 text="開始修改", 175 command=self.start) 176 button_start.place(x=165, y=130, width=70, height=30) 177 178 def matchcase(self, word): 179 return word 180 # def rmodify(m): 181 # # re.sub會將匹配到的對象,循環調用modify方法傳入 182 # 183 # # 獲取匹配的文本 184 # text = m.group() 185 # 186 # if text.isupper(): 187 # # 如果文本全部是大寫,就返回word的全部大寫模式 188 # return word.upper() 189 # elif text.islower(): 190 # # 如果文本全部是小寫,就返回word的全部小寫模式 191 # return word.lower() 192 # elif len(text) > 0 and text[0].isupper(): 193 # # 如果文本是首字母大寫,就返回word的首字母大寫模式 194 # return word.capitalize() 195 # else: 196 # # 其他情況,直接返回word 197 # return word 198 # 199 # return modify 200 201 def modify(self, path): 202 # 修改當前文件夾名稱 203 if self.folder_name.get() == 1: 204 folder = os.path.basename(path) 205 folder = re.sub(self.string_old.get(), 206 self.matchcase(self.string_new.get()), 207 # flags=re.IGNORECASE, 208 folder) 209 os.rename(path, os.path.join(os.path.dirname(path), folder)) 210 path = os.path.join(os.path.dirname(path), folder) 211 212 filenames = os.listdir(path) 213 logger.info(f"file list {filenames}") 214 215 for filename in filenames: 216 domain = os.path.abspath(path) 217 file_path = os.path.join(domain, filename) 218 219 # 遞歸修改子文件名稱、文件名稱、文件內容 220 if os.path.isdir(file_path): 221 if self.folder_name.get() == 1: 222 filename = re.sub(self.string_old.get(), 223 self.matchcase(self.string_new.get()), 224 # flags=re.IGNORECASE, 225 filename) 226 os.rename(file_path, os.path.join(domain, filename)) 227 file_path = os.path.join(domain, filename) 228 229 logger.debug(f"enter folder {file_path}") 230 self.modify(file_path) 231 logger.debug(f"exit folder {file_path}\n") 232 continue 233 234 # 修改文件名稱 235 if self.file_name.get() == 1: 236 filename = re.sub(self.string_old.get(), 237 self.matchcase(self.string_new.get()), 238 # flags=re.IGNORECASE, 239 filename) 240 os.rename(file_path, os.path.join(domain, filename)) 241 file_path = os.path.join(domain, filename) 242 243 # 修改文件內容 244 if self.file_content.get() == 1: 245 format = file_path.split(".")[-1] 246 if format != "c" and format != "h" and format != "txt": 247 logger.info(f"can not process {file_path}") 248 continue; 249 250 fread = open(file_path, 'r') 251 fwrite = open("%s.backup" % file_path, 'w') 252 253 while True: 254 line = fread.readline() 255 if len(line) > 0: 256 line = re.sub(self.string_old.get(), 257 self.matchcase(self.string_new.get()), 258 # flags=re.IGNORECASE, 259 line) 260 fwrite.write(line) 261 else: 262 break 263 fread.close() 264 fwrite.close() 265 os.remove(file_path) 266 os.rename("%s.backup" % file_path, file_path) 267 268 def start(self): 269 if self.path.get() == "": 270 tkinter.messagebox.showinfo('錯誤', "請選擇文件夾路徑!") 271 else: 272 logger.info(f'''路徑:"{self.path.get()}"''') 273 logger.info("修改選項:") 274 option_count = 0 275 if self.folder_name.get() == 1: 276 option_count = option_count + 1 277 logger.info(f" {option_count}. 文件夾名稱") 278 if self.file_name.get() == 1: 279 option_count = option_count + 1 280 logger.info(f" {option_count}. 文件名稱") 281 if self.file_content.get() == 1: 282 option_count = option_count + 1 283 logger.info(f" {option_count}. 文件內容") 284 logger.info(f"原字符串:{self.string_old.get()}") 285 logger.info(f"新字符串:{self.string_new.get()}") 286 self.modify(self.path.get()) 287 tkinter.messagebox.showinfo('結果', "修改完成") 288 289 def log(self): 290 os.startfile("log.txt") 291 # domain = os.path.abspath(os.getcwd()) 292 # log_path = os.path.join(domain, "log") 293 # 294 # log = open(log_path, 'r') 295 # log.close() 296 297 def rule(self): 298 tkinter.messagebox.showinfo('批量修改字符串規則', 299 "1.修改當前文件夾及子文件夾的名稱;\n" 300 "2.修改當前文件夾及子文件夾下所有文件的名稱;\n" 301 "3.修改當前文件夾及子文件夾下所有文件的內容;\n") 302 303 def about(self): 304 tkinter.messagebox.showinfo('批量修改字符串', 305 "作者:Risun_Lee\n" 306 "版本: V1.0\n" 307 "發布日期: 2020年9月8日\n") 308 309 def release_note(self): 310 tkinter.messagebox.showinfo('版本說明', 311 "V1.0:\n" 312 "1.支持文件夾名稱、文件名稱的修改;\n" 313 "2.支持txt、c、h文件內容的修改;\n") 314 315 def select_path(self): 316 path = tkinter.Tk() 317 path.withdraw() 318 fpath = os.path.normpath(tkinter.filedialog.askdirectory()) 319 if fpath != ".": 320 self.path.set(str(fpath)) 321 322 def main(): 323 create_logger(level=logging.DEBUG) 324 modify_string() 325 326 if __name__ == '__main__': 327 main()