4 Star 8 Fork 3

小流氓 / exporter

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
main.go 25.08 KB
一键复制 编辑 原始数据 按行查看 历史
小流氓 提交于 2023-07-31 18:15 . 生成Json
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
// export tool project main.go
package main
import (
"bufio"
"encoding/csv"
"flag"
"fmt"
"github.com/emirpasic/gods/lists/arraylist"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"syscall"
"unicode"
"github.com/emirpasic/gods/sets/hashset"
"github.com/emirpasic/gods/maps/hashmap"
"github.com/emirpasic/gods/maps/linkedhashmap"
"github.com/tealeg/xlsx"
"github.com/antlabs/strsim"
)
const (
FlagOnly = "[不可重复]"
DecimalConfig = "[小数配置]"
SpacesConfig = "[空格配置]"
StringFlag = "[字符串]"
ListFlag = "[List]"
NoTranslationFlag = "[不要翻译]"
)
var (
outPath *string //输出到指定目录
tplOutputDir string //TPL输出目录
pauseFlag *bool //当遇到错误是否暂停执行
zone *string //地区编号
allSheet *hashmap.Map //处理过的Sheet,key->sheetName,value->fileName
errTexts *hashset.Set //错误的文本
ignoreTpl *hashset.Set //忽略生成TPL
ignoreExcel *hashset.Set //忽略解析的Excel
i18nFlag *bool //是否开启I18N
dict map[string]string //翻译好的字典
allText *linkedhashmap.Map //需要翻译的文本
translatedText *linkedhashmap.Map //已翻译的文本(不包含翻译过已不使用的文本)
step *int //阶服
matchFlag *bool //相似度的显示
textSourceMap *hashmap.Map //文本来源
limit *int //Sheet名称长度限制
comma *int //生成的CSV分隔符
jsonFlag *bool //生成JSON
csvFlag *bool //生成CSV
)
func main() {
excelPath := flag.String("path", ".", "-path 指定CSV文件所在路径")
outPath = flag.String("out", ".", "-out 输出到指定目录")
pauseFlag = flag.Bool("pause", false, "-pause 当遇到错误是否暂停执行")
i18nFlag = flag.Bool("i18n", false, "-i18n 是否开启国际化功能")
matchFlag = flag.Bool("match", false, "-match 是否显示相似度的文本")
zone = flag.String("zone", "CN", "-zone 指定地区编号")
file := flag.String("file", "", "-file 需要单一导表的文件")
step = flag.Int("step", 1, "-step 阶服配置,默认为1:不开启")
limit = flag.Int("limit", 0, "-limit Sheet名称长度提醒,默认为0:不开启")
comma = flag.Int("comma", ' ', "-comma 生成的CSV分隔符,默认为Tab符")
jsonFlag = flag.Bool("json", false, "-json 是否生成JSON格式的文件")
csvFlag = flag.Bool("csv", true, "-csv 是否生成CSV格式的文件")
flag.Parse()
// 做一个特别的设定
if strings.EqualFold("CN", *zone) {
*i18nFlag = false
}
single := !strings.EqualFold("", *file) //标识当前是否为单一文件
var files = make([]string, 0, 512)
if single {
files = append(files, *file)
fmt.Printf("本次导表只处理单一配置文件\n")
} else {
files, _ = scanningExcelFiles(*excelPath) //扫描出所有Excel文件
fmt.Printf("本次导表一共扫描到%d个配置文件\n", len(files))
}
tplOutputDir = *outPath + "/data/" + *zone + "/"
// 开始阶服配置,那要加入阶服目录
if *step > 1 {
tplOutputDir = tplOutputDir + strconv.Itoa(*step) + "/"
}
if !single { //如果只导一个文件,那目标目录不能清理
cleanUpDataDir(tplOutputDir, ".tpl") //清理将要生成的TPL目录
if *jsonFlag {
cleanUpDataDir(tplOutputDir+"json/", ".json") //清理将要生成的JSON目录
}
}
allSheet = hashmap.New()
allText = linkedhashmap.New()
translatedText = linkedhashmap.New()
textSourceMap = hashmap.New()
errTexts = hashset.New()
ignoreTpl = hashset.New()
ignoreExcel = hashset.New()
errTexts.Add("#N/A", "#REF!", "#NAME?")
// 翻译好的字典
if *i18nFlag {
dict = i18nDict()
}
// 导表配置文件
initConfig(*excelPath)
// 遍历excel文件
for _, fileName := range files {
// 忽略不要解析的Excel,以便加速导表时间
if ignoreExcel.Contains(filepath.Base(fileName)) {
continue
}
//2003版本的给个提示,不作处理了
if strings.HasSuffix(fileName, ".xls") {
Error("\n\n警告:发现2003版本Excel配置[%s],智能忽略...\n", fileName)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
//处理Excel文件
if !single || strings.HasSuffix(fileName, ".xlsx") || strings.HasSuffix(fileName, ".xlsm") {
handleExcelFile(fileName)
} else {
Error("\n\n忽略非Excel文件[%s]\n", fileName)
}
}
fmt.Println()
if *i18nFlag {
handleI18n(allText)
}
fmt.Println()
fmt.Println("导出已完成")
fmt.Println()
}
// 初始化配置文件
func initConfig(path string) {
xlFile, err := xlsx.OpenFile(path + "/exporter.xlsx")
if err == nil {
for _, sheet := range xlFile.Sheets {
// 忽略TPL
if strings.EqualFold("忽略TPL", sheet.Name) {
for _, row := range sheet.Rows {
if len(row.Cells) == 0 { // 空行
continue
}
tplFileName := row.Cells[0].String()
if len(tplFileName) > 0 {
ignoreTpl.Add(tplFileName)
}
}
}
// 忽略解析的Excel
if strings.EqualFold("忽略Excel", sheet.Name) {
for _, row := range sheet.Rows {
if len(row.Cells) == 0 { // 空行
continue
}
excelFileName := row.Cells[0].String()
if len(excelFileName) > 0 {
ignoreExcel.Add(excelFileName)
}
}
}
}
}
}
//提取翻译好的字典
func i18nDict() map[string]string {
dict := make(map[string]string)
xlFile, err := xlsx.OpenFile(*outPath + "/i18n/" + *zone + ".xlsx")
if err == nil {
for _, sheet := range xlFile.Sheets {
for lineNum, row := range sheet.Rows {
if lineNum > 0 && len(row.Cells) >= 1 {
textKey := row.Cells[0].String()
if len(row.Cells) >= 2 && len(row.Cells[1].String()) > 0 {
// 已翻译
if _, ok := dict[textKey]; !ok {
// 日本的空格给换掉
text := row.Cells[1].String()
text = strings.ReplaceAll(text, " ", " ")
dict[textKey] = text
}
} else {
// 没翻译
allText.Put(textKey, "")
}
}
}
}
}
return dict
}
// 处理语言翻译的字典提取与合并
func handleI18n(allTextMap *linkedhashmap.Map) {
xlsxFile := xlsx.NewFile()
// 要翻译的
{
sheet, _ := xlsxFile.AddSheet("需要翻译的文字")
row := sheet.AddRow()
cell := row.AddCell()
cell.SetString("原始文字")
cell = row.AddCell()
cell.SetString("翻译文字")
array := make([]string, translatedText.Size())
if *matchFlag {
cell = row.AddCell()
cell.SetString("相似原始文字")
cell = row.AddCell()
cell.SetString("相似翻译文字")
for index, e := range translatedText.Keys() {
array[index] = e.(string)
}
fmt.Println("正在搜索相似翻译内容,时间可能有些长,您可以先去喝杯咖啡...")
}
index := 0
allTextMap.Each(func(key interface{}, value interface{}) {
row := sheet.AddRow()
cell := row.AddCell()
cell.SetString(key.(string))
// 查找相似翻译
if *matchFlag {
index++
fmt.Print(index)
fmt.Print("/")
fmt.Println(allTextMap.Size())
//去除所有尖括号内代码
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
testStr := re.ReplaceAllString(key.(string), "")
match := strsim.FindBestMatchOne(testStr, array)
if match.Score > 0.8 {
// 待翻译
row.AddCell()
// 相似源码
cell = row.AddCell()
cell.SetString(match.S)
// 相似源码
cell = row.AddCell()
v, exist := translatedText.Get(match.S)
if exist {
cell.SetString(v.(string))
}
}
}
})
}
// 历史记录
{
sheet, _ := xlsxFile.AddSheet("已翻译好的文字")
row := sheet.AddRow()
cell := row.AddCell()
cell.SetString("原始文字")
cell = row.AddCell()
cell.SetString("翻译文字")
cell = row.AddCell()
cell.SetString("文字来源")
for key := range dict {
_, exist := translatedText.Get(key)
if !exist {
translatedText.Put(key, dict[key])
}
}
translatedText.Each(func(key interface{}, value interface{}) {
row := sheet.AddRow()
row.AddCell().SetString(key.(string))
row.AddCell().SetString(value.(string))
// 有来源
tpl, found := textSourceMap.Get(key.(string))
if found {
row.AddCell().SetString(tpl.(string))
}
})
}
_ = xlsxFile.Save(*outPath + "/i18n/" + *zone + ".xlsx")
}
func Error(s string, a ...interface{}) {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
proc := kernel32.NewProc("SetConsoleTextAttribute")
handle, _, _ := proc.Call(uintptr(syscall.Stdout), uintptr(4|8)) //12 Red light
fmt.Printf(s, a...)
handle, _, _ = proc.Call(uintptr(syscall.Stdout), uintptr(7)) //White dark
CloseHandle := kernel32.NewProc("CloseHandle")
_, _, _ = CloseHandle.Call(handle)
}
// CheckNamingSpecification 检测标题行命令是否规范
func CheckNamingSpecification(list []string, sheetName string) {
aLen := len(list)
for i := 0; i < aLen; i++ {
if strings.Contains(list[i], " ") {
Error("\n\n警告:[%s]里发现标题行中包含空格命名字段[%s],请火速修正...\n", sheetName, list[i])
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
}
}
// CheckDuplicateTitle 检测重复的标题
func CheckDuplicateTitle(list []string, sheetName string) {
aLen := len(list)
for i := 0; i < aLen-1; i++ {
for x := i + 1; x < aLen; x++ {
if list[i] == list[x] {
Error("\n\n警告:[%s]里发现重复字段[%s],请火速修正...\n", sheetName, list[i])
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
}
}
}
func IsChineseChar(str string) bool {
for _, r := range str {
if unicode.Is(unicode.Scripts["Han"], r) || (regexp.MustCompile("[\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]").MatchString(string(r))) {
return true
}
}
return false
}
// IsZoneField 检查是否为版本化字段
func IsZoneField(str string) bool {
return strings.Contains(str, "(") || strings.Contains(str, ")")
}
//开始处理Excel文件
func handleExcelFile(fileName string) {
fmt.Println()
fmt.Print("正在处理:" + fileName)
xlFile, err := xlsx.OpenFile(fileName)
if err != nil {
fmt.Printf("%s", err)
}
// 这个Excel是否为自述文件(让工具忽略报警)
isDocFile := false
// 分析Sheet国际化版本
sheetMap := linkedhashmap.New()
for _, sheet := range xlFile.Sheets {
sheetName := sheet.Name
// 不是文档时,进行后缀判定
if !isDocFile && strings.HasSuffix(sheetName, ".doc") {
isDocFile = true
}
// 如果不是Tpl且不是国际化文件
if !strings.HasSuffix(sheetName, ".tpl") && !strings.HasSuffix(sheetName, ".i18n") {
// 不是描述文件,且有后续,要警告,基本上就是写错后续的情况
if !isDocFile && strings.Contains(sheetName, ".") {
Error("\n\n警告:文件[%s]里发现[%s]异常后缀配表,请火速修正...\n", fileName, sheet.Name)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
continue
}
// 发现空格警告提示
if strings.Contains(sheetName, " ") {
Error("\n\n警告:文件[%s]里发现[%s]命名中有空格,请火速修正...\n", fileName, sheet.Name)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
// 如果有(),就是国际化Sheet,处理名称进行覆盖之前配置
if strings.Contains(sheetName, "(") && strings.Contains(sheetName, ")") {
if *i18nFlag {
prefix := "(" + *zone + ")"
if strings.Contains(sheetName, prefix) {
sheetName = strings.ReplaceAll(sheetName, prefix, "")
} else {
continue //不是当前版本,那个配置直接忽略掉
}
} else {
continue //未开始国际化,那个配置直接忽略掉
}
}
// 如果有{},就是阶服配置
if strings.Contains(sheetName, "{") && strings.Contains(sheetName, "}") {
prefix := "{" + strconv.Itoa(*step) + "}"
if strings.Contains(sheetName, prefix) {
sheetName = strings.ReplaceAll(sheetName, prefix, "")
} else {
continue //不是当前版本,那个配置直接忽略掉
}
} else if *step > 1 {
continue
}
if *limit > 1 && strings.HasSuffix(sheetName, ".tpl") && len(sheetName) > 25 {
Error("\n\n警告:文件[%s]里发现[%s]名称有些长了,请火速修正...\n", fileName, sheet.Name)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
sheetMap.Put(sheetName, sheet)
}
//生成文件状态
genFileFlag := false
//开始处理Sheet
sheetMap.Each(func(key, sheet interface{}) {
if handleExcelSheet(fileName, key.(string), sheet.(*xlsx.Sheet)) {
genFileFlag = true
}
})
if *step <= 1 && !genFileFlag && !isDocFile {
//Error("\n这个Excel已没人使用了,请确认是否需要移除.\n")
//Error(fileName)
//Error("\n")
}
}
//开始处理Sheet
func handleExcelSheet(fileName string, sheetName string, sheet *xlsx.Sheet) bool {
if strings.HasSuffix(sheetName, ".tpl") {
// 如果Sheet名称是以.tpl结尾则为策划配置模板
return handleSheet(fileName, sheetName, sheet)
} else if *i18nFlag && strings.HasSuffix(sheetName, ".i18n") {
// 如果Sheet名称是以.i18n结尾则为需要翻译的文本
return handleSheet(fileName, sheetName, sheet)
}
//策划用的数据文件???
return true
}
//开始处理策划配置Sheet
func handleSheet(fileName string, sheetName string, sheet *xlsx.Sheet) bool {
// 如果这个SheetName是$filename.i18n,那要把他换成文件名
if strings.EqualFold("$filename.i18n", sheetName) {
// 先把文件名中的路径去了
_, fileName = filepath.Split(fileName)
//获取文件名称带后缀
fileNameWithSuffix := path.Base(fileName)
//获取文件的后缀(文件类型)
fileType := path.Ext(fileNameWithSuffix)
//获取文件名称(不带后缀)
sheetName = strings.TrimSuffix(fileNameWithSuffix, fileType) + ".i18n"
}
fmt.Print(" >> " + sheetName)
// 查找这个Sheet名称是否存在
CheckDuplicateSheetName(fileName, sheetName)
var data [][]string //CSV的内容
var titleFlag []bool //标题是否存在
var onlyFlag []bool //唯一判定
var decimalFlag []bool //允许小数配置标识
var spacesFlag []bool //禁止空格
var titleStringFlag []bool //这一列是否为字符串
var titleStringArray []int //原生下标对应CSV的下标
var titleListFlag []bool //这一列是否为字符串
var noTranslationFlag []bool //这一列是否为字符串
onlyMap := map[string]int{}
var zoneDataFlag []bool //版本化字段是否存在
var zoneIndexData []int //版本化字段所在列编号
// 申明一个标题最大数量
var titleMaxNum int = 0
// 遍历row
for lineNum, row := range sheet.Rows {
if row.Hidden {
Error("\n警告:[%s]里发现隐藏行lineNum=[%d],请取消隐藏...\n", sheetName, lineNum+1)
}
if lineNum == 0 { //标题行
var lineData []string //用来存这一行的数据
titleMaxNum = len(row.Cells)
titleFlag = make([]bool, titleMaxNum)
titleStringFlag = make([]bool, titleMaxNum)
titleStringArray = make([]int, titleMaxNum)
titleListFlag = make([]bool, titleMaxNum)
noTranslationFlag = make([]bool, titleMaxNum)
zoneDataFlag = make([]bool, titleMaxNum)
zoneIndexData = make([]int, titleMaxNum)
// 遍历cell
for index, cell := range row.Cells {
if cell.Hidden {
Error("\n\n警告:[%s]里发现隐藏列cellNum=[%d],请取消隐藏...\n", sheetName, index+1)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
v := cell.String()
if len(v) > 0 {
// 过滤掉版本化字段
if !IsZoneField(v) {
titleFlag[index] = true
lineData = append(lineData, strings.TrimSpace(v))
} else if *i18nFlag {
// 如果开启了国际化,那把此列对应上他所修正的列
var targetIndex = -1
for index, cell := range row.Cells {
subStr := "(" + *zone + ")" + cell.String()
if strings.EqualFold(subStr, v) {
targetIndex = index
}
}
if targetIndex >= 0 {
zoneDataFlag[targetIndex] = true
zoneIndexData[targetIndex] = index
}
}
}
}
// 检测标题行命令是否规范
CheckNamingSpecification(lineData, sheetName)
//标题编号不可以重复
CheckDuplicateTitle(lineData, sheetName)
data = append(data, lineData)
} else if lineNum == 1 { // 标题注释行
onlyFlag = make([]bool, titleMaxNum)
decimalFlag = make([]bool, titleMaxNum)
spacesFlag = make([]bool, titleMaxNum)
for index, cell := range row.Cells {
if index >= titleMaxNum {
continue
}
cellString := cell.String()
//不可重复
if strings.Contains(cellString, FlagOnly) {
onlyFlag[index] = true
}
//小数配置
if strings.Contains(cellString, DecimalConfig) {
decimalFlag[index] = true
}
//禁止空格
if strings.Contains(cellString, SpacesConfig) {
spacesFlag[index] = true
}
// 强制字符串
if strings.Contains(cellString, StringFlag) {
titleStringFlag[index] = true
}
// 强制List
if strings.Contains(cellString, ListFlag) {
titleListFlag[index] = true
}
// 不要翻译
if strings.Contains(cellString, NoTranslationFlag) {
noTranslationFlag[index] = true
}
}
} else if len(row.Cells) == 0 { // 空行
continue
} else {
// 数据注释行
v := row.Cells[0].String()
if strings.HasPrefix(v, "//") {
continue
}
hasData := false
var lineData []string //用来存这一行的数据
for index, cell := range row.Cells {
if index < titleMaxNum && titleFlag[index] {
v := cell.String()
// 存在国际化列,那要改要配置值
if zoneDataFlag[index] {
v = row.Cells[zoneIndexData[index]].String()
}
// 判定数据引用错误
if errTexts.Contains(v) {
Error("\n\n警告:[%s]里[%d]行中发现错误引用数据[%s],请火速修正...\n", sheetName, lineNum+1, v)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
//检查小数配置
if cell.Type() == 2 && !decimalFlag[index] {
if strings.Contains(v, ".") {
Error("\n\n%s", fileName)
Error("\n警告:[%s]里[%d]行中发现小数[%s],请火速修正...\n", sheetName, lineNum+1, v)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
} else if cell.Type() == 0 && !spacesFlag[index] {
if strings.Contains(v, " ") {
Error("\n\n%s", fileName)
Error("\n警告:[%s]里[%d]行中发现[%s]中有空格,请火速修正...", sheetName, lineNum+1, v)
Error("\n如果确定需要配置空格,请在第二行注释中添加[空格配置]\n")
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
}
// 国际化文本(这里移除了结束的换行)
i18nText := v
// 这个单元格里有不要翻译,那要把这个几个字去掉
hasNoTranslation := strings.Contains(i18nText, NoTranslationFlag)
if hasNoTranslation {
i18nText = strings.ReplaceAll(i18nText, NoTranslationFlag, "")
}
if *i18nFlag && IsChineseChar(i18nText) {
// 需要翻译
if !(noTranslationFlag[index] || hasNoTranslation) {
cao := i18nText
cao = strings.Trim(cao, "\n")
cao = strings.Trim(cao, " ")
cao = strings.Trim(cao, " ")
// 判定是不是已翻译好了
if text, ok := dict[cao]; ok {
translatedText.Put(i18nText, text)
textSourceMap.Put(i18nText, sheet.Name)
i18nText = strings.ReplaceAll(i18nText, cao, text)
} else {
allText.Put(i18nText, "")
}
}
}
lineData = append(lineData, i18nText)
// 类型判定
if titleStringFlag[index] || (!strings.EqualFold("", i18nText) && !IsNum(i18nText)) {
titleStringFlag[index] = true
}
titleStringArray[len(lineData)-1] = index
if len(i18nText) > 0 {
hasData = true
//唯一检查
if index < len(onlyFlag) && onlyFlag[index] {
if _, ok := onlyMap[i18nText]; ok {
Error("\n\n警告:[%s]里发现重复配置[%s],请火速修正...\n", sheetName, v)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
}
onlyMap[i18nText] = 1
}
}
}
}
if hasData {
// 由于Excel在读取会忽略后面的空白,所以在转CSV要补上
totalNum := 0
for index, v := range titleFlag {
if v {
totalNum++
// 还要忽略掉多出标题的配置
if totalNum < titleMaxNum && totalNum >= len(lineData) {
titleStringArray[totalNum-1] = index
}
}
}
for i := len(lineData); i < totalNum; i++ {
lineData = append(lineData, "")
}
data = append(data, lineData)
}
}
}
// 如果一列数据都没有,那就不要写文件了
totalNum := 0
for _, v := range titleFlag {
if v {
totalNum++
}
}
if totalNum == 0 {
Error("\n\n%s >> %s配置中一列数据都没有吗???\n", fileName, sheetName)
return false
}
//生成文件状态
genFileFlag := false
if *csvFlag && !ignoreTpl.Contains(sheetName) { // 生成TPL文件
f, err := os.Create(tplOutputDir + sheetName) //创建文件
if err != nil {
panic(err)
}
defer f.Close()
//f.WriteString("\xEF\xBB\xBF") // 写入UTF-8 BOM
w := csv.NewWriter(f)
w.Comma = rune(*comma)
w.WriteAll(data) //写入数据
w.Flush()
genFileFlag = true
}
// 是否生成JSON
if *jsonFlag {
if writerToJsonFile(fileName, sheetName, data, titleStringFlag, titleStringArray, titleListFlag) {
genFileFlag = true
}
}
return genFileFlag
}
// 生成JSON文件
func writerToJsonFile(fileName string, sheetName string, data [][]string, titleStringFlag []bool, titleStringArray []int, titleListFlag []bool) bool {
array := strings.SplitN(sheetName, ".", 2)
jsonFileName := array[0] + ".json"
// 生成的LUA文件
f, err := os.Create(tplOutputDir + "/json/" + jsonFileName) //创建文件
if err != nil {
panic(err)
}
defer f.Close()
titleLine := data[0]
list := arraylist.New()
for i, line := range data {
if i > 0 {
m := make(map[string]interface{})
for index, s := range line {
title := titleLine[index]
m[title] = s
}
list.Add(m)
}
}
marshal, err := list.ToJSON()
if err != nil {
panic(err)
}
f.Write(marshal)
//fmt.Println(string(marshal))
return true
}
func IsNum(s string) bool {
// 如果配置中有_就直接否定数字
if strings.Contains(s, "_") {
return false
}
// 能转化为数字的就算是数字
_, err := strconv.ParseFloat(s, 64)
return err == nil
}
// CheckDuplicateSheetName 检测是否存在重复的Sheet名称
func CheckDuplicateSheetName(fileName string, sheetName string) {
lowerSheetName := strings.ToLower(sheetName)
if v, ok := allSheet.Get(lowerSheetName); ok {
Error("\n\n警告:重复文件,请火速修正...\n")
Error("文件一:[%s]里有[%s]\n", v, sheetName)
Error("文件二:[%s]里有[%s]\n", fileName, sheetName)
if *pauseFlag {
Error("确认忽略请按回车键继续执行...\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()
}
} else {
allSheet.Put(lowerSheetName, fileName)
}
}
// 清理TPL输出目录
func cleanUpDataDir(dirPath string, suffix string) {
dir, err := ioutil.ReadDir(dirPath)
if err != nil {
_ = os.MkdirAll(dirPath, 777) //尝试创建这个目标文件夹(第一次这个是目录是不存在的)
return
}
for _, fi := range dir {
if fi.IsDir() {
continue
}
if strings.HasSuffix(fi.Name(), suffix) {
_ = os.Remove(dirPath + fi.Name())
}
}
_ = os.MkdirAll(dirPath, 777) //尝试创建这个目标文件夹(第一次这个是目录是不存在的)
}
// 扫描指定目录下所有Excel文件
// 后缀需要小写方式
func scanningExcelFiles(dirPth string) (files []string, err error) {
err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error { //遍历目录
// 忽略目录
if fi.IsDir() {
return nil
}
// 前缀为Excel打开文件也忽略掉
if strings.HasPrefix(fi.Name(), "~") {
return nil
}
//满足后缀要求的就是Excel
// 文件名称转化为小写字母
lowerFilename := strings.ToLower(filename)
if strings.HasSuffix(lowerFilename, ".xlsx") || strings.HasSuffix(lowerFilename, ".xlsm") || strings.HasSuffix(lowerFilename, ".xls") {
files = append(files, filename)
}
return nil
})
return files, err
}
Go
1
https://gitee.com/xiaoe/exporter.git
git@gitee.com:xiaoe/exporter.git
xiaoe
exporter
exporter
master

搜索帮助