最近事情比较多,一直没更新内容,今天有时间给大家分享一下前几天做的一个小脚本吧!脚本诞生的背景是因为项目国际化业务需求,项目要支持多语言,但是一个项目中涉及到的中文内容可不少啊,vue多语言插件用的vue-i18n,网上也有命令行工具vue-i18n-cli进行自动化处理,但是这个插件不能满足我们的业务需求,所有的语言key需要语义化,且维护多语言的工作不在本地进行,因为中台部下面N多项目,不可能每个项目都自己去维护自己的多语言问题,所以就诞生了一个多语言数据维护平台!那么如果配合这个平台进行项目调整就是我们需要思考的了,因为我这边考虑的比较多,而且主要负责的项目就有两个,还不算协助的项目,如果都需要前端手动去改内容当中的中文然后去平台维护那人工成本太高了,所以就和架构师聊了一下,我去开发个自动化脚本,他去针对我的脚本在多语言平台进行一个对接,这样的话至少第一步的获取中文维护平台数据的工作就相当轻松了!目前脚本第一个版本已经做好了,主要实现的是将项目中的中文抽离去重,然后导入数据平台,后期会考虑做一下数据反填,具体业务还得看实际情况再定吧!
说下开发脚本这个问题吧!那第一步我们需要对脚本的功能流程及界面进行一个方案设计和梳理!
我用菜鸟工具在线画了一个简单的界面图,毕竟功能不复杂比较简单,而且也是内部使用,所以简简单单就好!
首先梳理下思路,通过界面我们了解到需要先去开发应用界面,主要用的是python GUI编程,其实我也不会,不会没关系,有官网,有百度!把GUI给啃完了,那界面也出来了!
界面出来了,第二步我们开始写功能,首先解决选择路径的问题,这里主要是用的Tkinter、os、tkMessageBox、tkFileDialog这几个模块,*注意,我这里是以python2.7版本为基础的,所以导入模块的时候要注意名称不要和3.0以上版本混淆!
选择路径的问题解决了,那我们就开始写执行的功能!执行的逻辑是这样的,选择目录路径是以组的概念存在的(配合数据平台),每次执行生成的excel也是以组的名称命名,命名我直接使用了导航目录作为组,然后将生成的excel放在存放路径下,具体的内容稍后会放在代码内供大家了解!两个路径必须都要有,否则会弹出提示!
第三步就是生成excel,这里用的是xlsxwriter模块,需要注意的是要设置统一的编码,所以还要用到sys
import os import re import Tkinter, tkMessageBox, tkFileDialog import xlsxwriter import sys reload(sys) sys.setdefaultencoding("utf-8")以上就是脚本用到的所有模块,正则这里着重说一下!
reTemp = re.compile('([^\w\s\<\>\-\--\{\}\[\]\(\)\&\$\@\*\;\:\'\"\,\+\=\?\!\%\#\|]+)+?') #逆向判断获取中文正则匹配中文我是这样做的,算是逆向判断了,和用[\u4e00-\u9fa5]效果差不多,但是比较偷懒,直接用[^\w\s]替代了,这个^大家可能都知道是匹配起始位置,但是配合方括号会有排除功能,刚开始在这块就踩了个坑,匹配不到中文!可能是我正则没学好吧(相信知道这个坑的没几个人吧,哈哈哈)!然后排除掉所有特殊字符,那么中文就匹配到了!匹配到之后就是去重,有个内置set方法可以直接使用!
最后就是把处理好的内容写到excel了!至此开发功能阶段也就基本结束了!
下面附上代码,供大家学习交流哈,第一次写,逻辑和方法都不是很完善,有懂得大神可以指正,我会继续完善!
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import re import Tkinter, tkMessageBox, tkFileDialog import xlsxwriter import sys reload(sys) sys.setdefaultencoding("utf-8") modal = Tkinter.Tk() ''' 绘制界面 ''' class CreateWindow(object): # 初始化设置窗口标题及出现位置 def __init__(self, name, width, height): modal.title(name) # 设置标题 # modal.iconbitmap(icon) # 设置图标 screen_width = modal.winfo_screenwidth() # 获取屏幕宽度 screen_height = modal.winfo_screenheight() # 获取屏幕高度 x = (screen_width - width) / 2 y = (screen_height - height) / 2 modal.geometry('%dx%d+%d+%d' % (width,height,x,y)) # 格式化参数,设置窗口居中 self.getPath = "" # 设置窗口内容标题及相关描述 def createContent(self,title,text): # tkMessageBox.showinfo(name,"ok了") Tkinter.Label(modal, text=title, pady=20, font=("微软雅黑", 18, "bold"), fg="#40a9ff").pack() Tkinter.Label(modal, text=text, width=200, font=("微软雅黑", 12), fg="#333").pack() ''' 抽离项目中指定目录下的中文并按组导出excel ''' class Excel(object): # 初始化,设置文件名,获取所选目录名为文件名及组名 def __init__(self,dirname,build_file_path): split_name =dirname[dirname.rfind('/'):] # 处理获取所选目录的路径名称并截取 self.group_name = split_name[1:] self.book = xlsxwriter.Workbook(build_file_path +'/'+self.group_name+'.xlsx') # 生成excel文件并沿用截取路径的名称 self.sheet = self.book.add_worksheet() self.dataSource = [] # 处理中文抽离 def file_extrac(self,dirname): lineList = [] for maindir,subdir,file_name_list in os.walk(dirname): for filename in file_name_list: allPath = os.path.join(maindir,filename) with open(allPath,"r") as fileList: for line in fileList.readlines(): if ("//" in line) or ("<!--" in line) or ("/*" in line): continue else: reTemp = re.compile('([^\w\s\<\>\-\--\{\}\[\]\(\)\&\$\@\*\;\:\'\"\,\+\=\?\!\%\#\|]+)+?') #逆向判断获取中文 reResult = reTemp.findall(str(line)) if reResult: #将非空行数据追加数组 for item in reResult: lineList.append(item) self.dataSource = lineList # 写入列名/表头 def write_colume_name(self, colums_name): for i in range(0, len(colums_name)): self.sheet.write(0, i, colums_name[i]) # 写入数据 def write_content(self): data = [] for item in set(self.dataSource): data.append(item) for i in range(len(data)): self.sheet.write(i+1,0,self.group_name) #第一个参数行,第二个参数列,第三个参数数据,写入组名 self.sheet.write(i+1,2,data[i]) #第一个参数行,第二个参数列,第三个参数数据,写入数据 # 关闭文件 def close(self): self.book.close() def getSelect(): global getPath getPath = tkFileDialog.askdirectory() labelText1.configure(text= getPath) def saveSelect(): global savePath savePath = tkFileDialog.askdirectory() labelText2.configure(text= savePath) def handleExcute(): if getPath and savePath: colums_name = ['组', '字段', '中文'] book = Excel(getPath,savePath) book.file_extrac(getPath) book.write_colume_name(colums_name) book.write_content() tkMessageBox.showinfo("成功","执行成功!") book.close() # sys.exit() #暂时注释,待后期完善是否继续功能 else: tkMessageBox.showinfo("警告", "请选择相关路径!") if __name__ == "__main__": global getPath, savePath getPath = "" savePath = "" ''' 设置窗口属性 ''' # icon = "D:\WorkSpace\setup\exeico.ico" # 必须为绝对路径,否则打包exe应用会报错 window = CreateWindow("自动化抽离脚本 v_1.0", 600, 400) window.createContent("使用说明", "本脚本仅适用于项目内部,\n所选目录即为组的概念,\n如遇脚本执行报错或异常等情况请联系业务中台部!") ''' 设置窗口功能 ''' frame = Tkinter.LabelFrame(modal, text=" 文件地址 ") # 定义样式容器 frame.pack(padx=15, pady=35) labelName1 = Tkinter.Label(frame, text= '目录路径:') # 定义label labelName1.grid(row=0, column=0, pady=6, padx=8) labelText1 = Tkinter.Label(frame, width=50) # 定义label后的value内容 labelText1.grid(row=0, column=1, pady=6, padx=8) labelButton1 = Tkinter.Button(frame, text="选择", width=6, fg="#fff", bg="#40a9ff", activeforeground="#fff", bd=0, activebackground="#40a9ff", command=getSelect) # 定义按钮 labelButton1.grid(row=0, column=2, pady=6, padx=8) labelName2 = Tkinter.Label(frame, text= '存放路径:') # 定义label labelName2.grid(row=1, column=0, pady=6, padx=8) labelText2 = Tkinter.Label(frame, width=50) # 定义label后的value内容 labelText2.grid(row=1, column=1, pady=6, padx=8) labelButton2 = Tkinter.Button(frame, text="选择", width=6, fg="#fff", bg="#40a9ff", activeforeground="#fff", bd=0, activebackground="#40a9ff", command=saveSelect) # 定义按钮 labelButton2.grid(row=1, column=2, pady=6, padx=8) labelExcute = Tkinter.Button(modal, text="执行", width=20, pady=6, fg="#fff", bg="#40a9ff", activeforeground="#fff", bd=0, activebackground="#40a9ff", command=handleExcute) labelExcute.pack() modal.mainloop()最后就对脚本进行一个封装,使其可以独立在不需要python环境的windows系统下允许,这里主要用的是py2exe模块,也没啥可以多说的,代码附上!
""" setup.py""" from distutils.core import setup import py2exe import sys #this allows to run it with a simple double click. sys.argv.append('py2exe') setup( version = "1.0.0", windows = [{"script":"projectScript.py","icon_resources":[(1,"exeico.ico")]}] )至此脚本应用就完成了,分享给大家!后续有时间的话会继续完善,包括反填数据的功能!