excel_to_lua.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. # -*- coding: utf-8 -*-
  2. '''
  3. 一、支持的表头
  4. 单值Key-Value形式的:【KV】、【MAP】;即第2行是key,第3行是类型,第5行是value
  5. 如:{a=1, b=3, ...}
  6. 单值Key-Value形式的:【K-V】;即第1列是key,第2列是类型,第4列是value
  7. 如:{a=1, b=3, ...}
  8. 对象列表形式的:【V】;即第1列
  9. 如:{1, 2, 3, ...}
  10. 对象Key-Value形式的:【M】;
  11. 如:{[1]={a=1, b=3, ...}, [2]={a=1, b=3, ...}}
  12. 单值列表形式的:【LIST】、【L】。
  13. 如:{{a=1, b=3, ...}, {a=1, b=3, ...}}
  14. 推荐使用:
  15. 单值Key-Value形式的:【K-V】
  16. 对象列表形式的:【V】
  17. 对象Key-Value形式的:【M】
  18. 单值列表形式的:【L】
  19. 二、支持的数据类型:
  20. 整数:int;
  21. 整数字符串:intstring;
  22. 布尔值:bool、boolean。为true的值:"TRUE"、"true"、"T"、"1"、1:
  23. 字符串:text、string;
  24. 浮点型:double、float;
  25. lua表达式:table、lua;
  26. 如:{{id=101,count=2222}}
  27. 其它:直接用文本输出。
  28. '''
  29. from fileinput import filename
  30. import os
  31. import sys
  32. import shutil
  33. # from tkinter import filedialog
  34. import ConfigParser
  35. import json
  36. import math
  37. import time
  38. from optparse import OptionParser
  39. from xlrd import open_workbook
  40. import commands
  41. reload(sys)
  42. sys.setdefaultencoding('utf-8')
  43. class ConfigParserEx(ConfigParser.ConfigParser):
  44. def __init__(self, defaults=None):
  45. ConfigParser.ConfigParser.__init__(self, defaults=None)
  46. def optionxform(self, optionstr):
  47. return optionstr
  48. def load_config(path):
  49. ''' 读取配置表
  50. '''
  51. config = ConfigParserEx()
  52. config.read(path)
  53. return config
  54. kSpace = " "
  55. class ExcaleToLuaClass(object):
  56. def __init__(self):
  57. self.currentPyPath = sys.path[0]
  58. self.configPath = None
  59. self.luaList = []
  60. def start(self):
  61. print("开始拷贝...")
  62. print("++++ 检查参数...")
  63. ok = self.check_arguments()
  64. if ok:
  65. print("---- 检查参数正确!!!")
  66. else:
  67. print("---- 检查参数错误!!!")
  68. return
  69. print("++++ 加载配置...")
  70. ok = self.load_arguments_config()
  71. if ok:
  72. print("---- 加载配置正确!!!")
  73. else:
  74. print("---- 加载配置错误!!!")
  75. return
  76. print("++++ 转换...")
  77. ok = self.loop_exchange()
  78. if ok:
  79. print("---- 转换正确!!!")
  80. else:
  81. print("---- 转换错误!!!")
  82. return
  83. self.check_lua()
  84. # self.print_file_map()
  85. def check_arguments(self):
  86. ''' 检查参数
  87. '''
  88. parser = OptionParser()
  89. parser.add_option("-s", action="store", type="string",
  90. dest="source", help="source path")
  91. parser.add_option("-o", action="store", type="string",
  92. dest="output", help="output path")
  93. parser.add_option("-t", action="store", type="string",
  94. dest="type", help="type")
  95. parser.add_option("-l", action="store", type="string",
  96. dest="lua", help="need check lua")
  97. (options, args) = parser.parse_args()
  98. sourcePath = options.source
  99. if options.source == None:
  100. print("-s config path is not set")
  101. outputPath = options.output
  102. if options.output == None:
  103. # 如果输出目录没有写,则在源目录中新建一个output目录作为输出目录
  104. outputPath = os.path.join(self.currentPyPath, "out")
  105. onlyClient = False
  106. if options.type == "c":
  107. onlyClient = True
  108. else:
  109. onlyClient = False
  110. onlyServer = False
  111. if options.type == "s":
  112. onlyServer = True
  113. else:
  114. onlyServer = False
  115. try:
  116. sourcePath = unicode(sourcePath, 'gbk')
  117. except Exception as e:
  118. pass
  119. try:
  120. outputPath = unicode(outputPath, 'gbk')
  121. except Exception as e:
  122. pass
  123. print("sourcePath", sourcePath)
  124. print("outputPath", outputPath)
  125. if not os.path.exists(outputPath):
  126. os.makedirs(outputPath)
  127. self.excelDirList = [""]
  128. self.luaDirList = [""]
  129. self.configRoot = ""
  130. self.needCheckLua = options.lua != None
  131. self.excelRootPath = sourcePath
  132. self.luaRootPath = outputPath
  133. if onlyClient:
  134. self.mode = "CLIENT"
  135. elif onlyServer:
  136. self.mode = "SERVER"
  137. else:
  138. self.mode = "ALL"
  139. return True
  140. def load_arguments_config(self):
  141. ''' 加载参数
  142. '''
  143. return True
  144. def add_lua_info(self, fileDir, filename, excelName, label, excelMode):
  145. ''' 记录lua信息
  146. '''
  147. self.luaList.append({
  148. "fileDir": fileDir,
  149. "filename": filename,
  150. "excelName": excelName,
  151. "label": label,
  152. "excelMode": excelMode
  153. })
  154. def check_lua(self):
  155. ''' 检查lua是否有语法错误
  156. '''
  157. if not self.needCheckLua:
  158. return
  159. hasError = False
  160. for v in self.luaList:
  161. excelName = v["excelName"]
  162. fileDir = v["fileDir"]
  163. filename = v["filename"]
  164. ok = self.checkLua(fileDir, filename)
  165. if not ok:
  166. hasError = True
  167. msg = "\033[31m---- lua语法错误:{0},{1}\033[0m".format(
  168. excelName, filename)
  169. print(msg)
  170. if not hasError:
  171. print("\033[32m---- 无lua语法错误\033[0m")
  172. def checkLua(self, fileDir, filename):
  173. ''' 检查lua是否有语法错误
  174. '''
  175. cmdFormat = 'lua -e \" \
  176. package.path = [[{0}?.lua;]] .. package.path; \
  177. local ok, err = pcall(require, [[{1}]]) \
  178. print(ok); \
  179. \"'
  180. cmd = cmdFormat.format(fileDir, filename)
  181. content = commands.getoutput(cmd)
  182. if content == "true":
  183. return True
  184. else:
  185. return False
  186. def print_file_map(self):
  187. ''' 打印文件信息:每个excel包含哪些配置
  188. '''
  189. if not self.needCheckLua:
  190. return
  191. strList = []
  192. for v in self.luaList:
  193. filename = v["filename"]
  194. excelName = v["excelName"]
  195. label = v["label"]
  196. excelMode = v["excelMode"]
  197. strList.append(",".join([excelName, filename, label, excelMode]))
  198. strList.sort()
  199. content = "\n".join(strList)
  200. excelRootPath = self.excelRootPath
  201. fo = open(excelRootPath + "/../excel-lua.csv", "w")
  202. fo.write(content)
  203. fo.close()
  204. def loop_exchange(self):
  205. try:
  206. ok = self.loop_exchange_try()
  207. except Exception, err:
  208. ok = False
  209. print("error", err)
  210. return ok
  211. def loop_exchange_try(self):
  212. ''' 循环转换
  213. '''
  214. excelDirList = self.excelDirList
  215. luaDirList = self.luaDirList
  216. excelRootPath = self.excelRootPath
  217. luaRootPath = self.luaRootPath
  218. configRoot = self.configRoot
  219. mode = self.mode
  220. for i in range(0, len(excelDirList)):
  221. excelDir = excelDirList[i]
  222. luaDir = luaDirList[i]
  223. sourcePath = os.path.join(excelRootPath, excelDir)
  224. outputPath = os.path.join(luaRootPath, luaDir, configRoot)
  225. if not os.path.exists(outputPath):
  226. os.makedirs(outputPath)
  227. dirList = []
  228. # 填充所有目录和文件名称
  229. for dirpath, dirnames, filenames in os.walk(sourcePath):
  230. for filename in filenames:
  231. dirList.append(os.path.join(dirpath, filename))
  232. # 过滤文件
  233. for filePath in dirList:
  234. name, ext = os.path.splitext(filePath)
  235. if ext == ".xlsx":
  236. i = name.find("~$")
  237. if i < 0:
  238. # 批量创建
  239. self.excel2lua(filePath, outputPath, mode)
  240. return True
  241. # 生成lua文件
  242. def excel2lua(self, filePath, outputPath, mode):
  243. ''' 转换
  244. '''
  245. fileName = os.path.basename(filePath)
  246. excelData = self.openExecl(filePath)
  247. # 遍历所有的sheet
  248. for sheet in excelData.sheets():
  249. name = sheet.name
  250. nrows = sheet.nrows
  251. ncols = sheet.ncols
  252. # print(nrows, ncols)#行列数
  253. # row 1 作为lua表的属性用
  254. row_1 = sheet.row_values(0)
  255. dataMode = row_1[0]
  256. excelMode = row_1[1]
  257. sheetLabel = ""
  258. if len(row_1) > 2:
  259. sheetLabel = row_1[2]
  260. sheetLabel = str(sheetLabel)
  261. if dataMode == "" or excelMode == "":
  262. continue
  263. if mode != "ALL":
  264. if mode == "CLIENT" and (excelMode != "CLIENT" and excelMode != "ALL"):
  265. # 只需要导出客户端需要的,该表不是客户端需要的,过掉
  266. continue
  267. elif mode == "SERVER" and (excelMode != "SERVER" and excelMode != "ALL"):
  268. # 只需要导出客户端需要的,该表不是客户端需要的,过掉
  269. continue
  270. outputOk = False
  271. outputFilePath = os.path.join(outputPath, name + ".lua")
  272. if dataMode == "K-V":
  273. outputOk = self.outputColKeyValue(sheet, outputFilePath)
  274. elif dataMode == "V":
  275. outputOk = self.outputList(sheet, outputFilePath)
  276. elif dataMode == "M":
  277. outputOk = self.outputObjMap(sheet, outputFilePath)
  278. elif dataMode == "L":
  279. outputOk = self.outputObjList(sheet, outputFilePath)
  280. # 下面是兼容旧版本的标签
  281. elif dataMode == "KV" or dataMode == "MAP":
  282. outputOk = self.outputKeyValue(sheet, outputFilePath)
  283. elif dataMode == "LIST":
  284. outputOk = self.outputObjList(sheet, outputFilePath)
  285. else:
  286. pass
  287. if outputOk:
  288. self.add_lua_info(outputPath, name, fileName,
  289. sheetLabel, excelMode)
  290. # 打开execl
  291. def openExecl(self, filePath):
  292. try:
  293. print("openExecl file name : ", filePath)
  294. data = open_workbook(filePath)
  295. return data
  296. except Exception, e:
  297. print("openExecl error:" + str(e))
  298. def cellValue(self, value, typeStr):
  299. ret = ""
  300. if value == "":
  301. return ""
  302. if value == "无" and typeStr != "text":
  303. return ""
  304. if typeStr == "int":
  305. retInt = float(value)
  306. ret = str(int(math.floor(retInt + 0.5)))
  307. elif typeStr == "intstring":
  308. if type(value) == type(0.1):
  309. retInt = float(value)
  310. ret = "\'" + str(int(math.floor(retInt + 0.5))) + "\'"
  311. else:
  312. ret = "\'" + str(value) + "\'"
  313. elif typeStr == "bool" or typeStr == "boolean":
  314. if value == "TRUE" or value == "true" or value == "T" or value == "1" or value == 1:
  315. ret = "true"
  316. else:
  317. ret = "false"
  318. elif typeStr == "text" or typeStr == "string":
  319. ret = "\'" + str(value) + "\'"
  320. elif typeStr == "double" or typeStr == "float":
  321. ret = str(value)
  322. elif typeStr == "table" or typeStr == "lua":
  323. ret = str(value)
  324. else:
  325. ret = str(value)
  326. return ret
  327. # 以Map形式输出 {a=1, b=3, ...}
  328. def outputColKeyValue(self, sheet, outputFilePath):
  329. name = sheet.name
  330. nrows = sheet.nrows
  331. ncols = sheet.ncols
  332. # print(nrows, ncols)#行列数
  333. output = open(outputFilePath, "w")
  334. output.write("local root = {")
  335. # 从第2行开始读
  336. start_rr = 1
  337. # 第一行需要特殊处理
  338. firstLine = True
  339. for x in xrange(start_rr, nrows):
  340. onRow = sheet.row_values(x)
  341. keyStr = onRow[0]
  342. # 忽略key是空的列
  343. if keyStr == "":
  344. continue
  345. valueType = onRow[1]
  346. value = onRow[3]
  347. valueStr = self.cellValue(value, valueType)
  348. # 忽略空值的属性
  349. if valueStr == "":
  350. continue
  351. if firstLine:
  352. output.write("\n" + kSpace + keyStr + " = " + valueStr)
  353. firstLine = False
  354. else:
  355. output.write(",\n" + kSpace + keyStr + " = " + valueStr)
  356. output.write("\n}\nreturn root")
  357. output.close()
  358. return True
  359. # 以List形式输出 {1, 2, 3, ...}
  360. def outputList(self, sheet, outputFilePath):
  361. nrows = sheet.nrows
  362. ncols = sheet.ncols
  363. # print(nrows, ncols)#行列数
  364. # 第3行是数据类型的声明
  365. typeRow = sheet.row_values(2)
  366. # 因为是list,就一个类型
  367. valueType = typeRow[0]
  368. output = open(outputFilePath, "w")
  369. output.write("local root = {")
  370. # 从第5行开始读
  371. start_rr = 4
  372. # 第一行需要特殊处理
  373. firstLine = True
  374. for x in xrange(start_rr, nrows):
  375. onRow = sheet.row_values(x)
  376. value = onRow[0]
  377. valueStr = self.cellValue(value, valueType)
  378. if firstLine:
  379. output.write("\n" + kSpace + valueStr)
  380. firstLine = False
  381. else:
  382. output.write(",\n" + kSpace + valueStr)
  383. output.write("\n}\nreturn root")
  384. output.close()
  385. return True
  386. # 以Map形式输出 {[1]={a=1, b=3, ...}, [2]={a=1, b=3, ...}}
  387. def outputObjMap(self, sheet, outputFilePath):
  388. name = sheet.name
  389. nrows = sheet.nrows
  390. ncols = sheet.ncols
  391. # print(nrows, ncols)#行列数
  392. # 支持合并单元格
  393. merge = {}
  394. for (rlow, rhigh, clow, chigh) in sheet.merged_cells:
  395. for r in xrange(rlow, rhigh):
  396. if not merge.get(r):
  397. merge[r] = {}
  398. for c in xrange(clow, chigh):
  399. merge[r][c] = sheet.row_values(rlow)[clow]
  400. # 第1行的第3个单元格声明哪个作为key
  401. row_1 = sheet.row_values(0)
  402. key = row_1[2]
  403. # 第2行是key名称
  404. keyRow = sheet.row_values(1)
  405. # 第3行是数据类型的声明
  406. typeRow = sheet.row_values(2)
  407. output = open(outputFilePath, "w")
  408. output.write("local root = {")
  409. # 从第0列开始读
  410. start_cc = 0
  411. # 从第5行开始读
  412. start_rr = 4
  413. # 第一行需要特殊处理
  414. firstLine = True
  415. for x in xrange(start_rr, nrows):
  416. objStr = "{"
  417. keyValue = ""
  418. # 读取一行
  419. oneRow = sheet.row_values(x)
  420. mergeRow = merge.get(x)
  421. # 第一个属性需要特殊处理
  422. firstProperty = True
  423. for cc in xrange(start_cc, ncols):
  424. keyStr = keyRow[cc]
  425. # 忽略key是空的列
  426. if keyStr == "":
  427. continue
  428. value = oneRow[cc]
  429. valueType = typeRow[cc]
  430. if mergeRow:
  431. mergeCell = mergeRow.get(cc)
  432. if mergeCell != None:
  433. value = mergeCell
  434. value = self.cellValue(value, valueType)
  435. if value == "":
  436. continue
  437. if firstProperty:
  438. objStr = objStr + "\n" + kSpace + kSpace + keyStr + " = " + value
  439. firstProperty = False
  440. else:
  441. objStr = objStr + ",\n" + kSpace + kSpace + keyStr + " = " + value
  442. if keyStr == key:
  443. keyValue = value
  444. if firstLine:
  445. objStr = "\n" + kSpace + \
  446. "[" + keyValue + "] = " + objStr + "\n" + kSpace + "}"
  447. firstLine = False
  448. else:
  449. objStr = ",\n" + kSpace + \
  450. "[" + keyValue + "] = " + objStr + "\n" + kSpace + "}"
  451. output.write(objStr)
  452. output.write("\n}\nreturn root")
  453. output.close()
  454. return True
  455. # 以Map形式输出 {{a=1, b=3, ...}, {a=1, b=3, ...}}
  456. def outputObjList(self, sheet, outputFilePath):
  457. name = sheet.name
  458. nrows = sheet.nrows
  459. ncols = sheet.ncols
  460. # print(nrows, ncols)#行列数
  461. # 支持合并单元格
  462. merge = {}
  463. for (rlow, rhigh, clow, chigh) in sheet.merged_cells:
  464. for r in xrange(rlow, rhigh):
  465. if not merge.get(r):
  466. merge[r] = {}
  467. for c in xrange(clow, chigh):
  468. merge[r][c] = sheet.row_values(rlow)[clow]
  469. # 第2行是key名称
  470. keyRow = sheet.row_values(1)
  471. # 第3行是数据类型的声明
  472. typeRow = sheet.row_values(2)
  473. output = open(outputFilePath, "w")
  474. output.write("local root = {")
  475. # 从第0列开始读
  476. start_cc = 0
  477. # 从第5行开始读
  478. start_rr = 4
  479. # 第一行需要特殊处理
  480. firstLine = True
  481. for x in xrange(start_rr, nrows):
  482. # 读取一行
  483. onRow = sheet.row_values(x)
  484. mergeRow = merge.get(x)
  485. # 检查这行是否有值
  486. hasValue = False
  487. for cc in xrange(start_cc, ncols):
  488. keyStr = keyRow[cc]
  489. # 忽略key是空的列
  490. if keyStr == "":
  491. continue
  492. # 忽略空值的属性
  493. value = onRow[cc]
  494. if mergeRow:
  495. mergeCell = mergeRow.get(cc)
  496. if mergeCell != None:
  497. value = mergeCell
  498. if value == "":
  499. continue
  500. hasValue = True
  501. # 这行没值,跳过
  502. if not hasValue:
  503. continue
  504. if firstLine:
  505. output.write("\n" + kSpace + "{")
  506. firstLine = False
  507. else:
  508. output.write(",\n" + kSpace + "{")
  509. # 第一个属性需要特殊处理
  510. firstProperty = True
  511. for cc in xrange(start_cc, ncols):
  512. keyStr = keyRow[cc]
  513. # 忽略key是空的列
  514. if keyStr == "":
  515. continue
  516. value = onRow[cc]
  517. valueType = typeRow[cc]
  518. if mergeRow:
  519. mergeCell = mergeRow.get(cc)
  520. if mergeCell != None:
  521. value = mergeCell
  522. valueStr = self.cellValue(value, valueType)
  523. # 忽略空值的属性
  524. if valueStr == "":
  525. continue
  526. if firstProperty:
  527. output.write("\n" + kSpace + kSpace +
  528. keyStr + " = " + valueStr)
  529. firstProperty = False
  530. else:
  531. output.write(",\n" + kSpace + kSpace +
  532. keyStr + " = " + valueStr)
  533. output.write("\n" + kSpace + "}")
  534. output.write("\n}\nreturn root")
  535. output.close()
  536. return True
  537. # 以Map形式输出 {a=1, b=3, ...}
  538. def outputKeyValue(self, sheet, outputFilePath):
  539. name = sheet.name
  540. nrows = sheet.nrows
  541. ncols = sheet.ncols
  542. # print(nrows, ncols)#行列数
  543. # 支持合并单元格
  544. merge = {}
  545. for (rlow, rhigh, clow, chigh) in sheet.merged_cells:
  546. for r in xrange(rlow, rhigh):
  547. if not merge.get(r):
  548. merge[r] = {}
  549. for c in xrange(clow, chigh):
  550. merge[r][c] = sheet.row_values(rlow)[clow]
  551. # 第2行是key名称
  552. keyRow = sheet.row_values(1)
  553. # 第3行是数据类型的声明
  554. typeRow = sheet.row_values(2)
  555. # 第3行是值
  556. valueRow = sheet.row_values(4)
  557. mergeRow = merge.get(4)
  558. output = open(outputFilePath, "w")
  559. output.write("local root = {")
  560. # 从第0列开始读
  561. start_cc = 0
  562. # 第一行需要特殊处理
  563. firstLine = True
  564. for cc in xrange(start_cc, ncols):
  565. keyStr = keyRow[cc]
  566. # 忽略key是空的列
  567. if keyStr == "":
  568. continue
  569. value = valueRow[cc]
  570. valueType = typeRow[cc]
  571. if mergeRow:
  572. mergeCell = mergeRow.get(cc)
  573. if mergeCell != None:
  574. value = mergeCell
  575. valueStr = self.cellValue(value, valueType)
  576. # 忽略空值的属性
  577. if valueStr == "":
  578. continue
  579. if firstLine:
  580. output.write("\n" + kSpace + keyStr + " = " + valueStr)
  581. firstLine = False
  582. else:
  583. output.write(",\n" + kSpace + keyStr + " = " + valueStr)
  584. output.write("\n}\nreturn root")
  585. output.close()
  586. return True
  587. def main():
  588. # try:
  589. ExcaleToLuaClass().start()
  590. # except Exception as e:
  591. # print "数据导出异常,请处理,问题如下(对应EXCEL为以上最后一个EXCEL):"
  592. # print e.message
  593. # time.sleep(20)
  594. if __name__ == '__main__':
  595. main()