策划CSV转JSON共享
这里可以 参考样例
日常的游戏开发中, 策划编辑配置表一般都是通过 Excel 在 Windows 环境进行配置,
如果是传统的 APP 开发, 一般都是在 WEB 网页端进行配置(在生成 JSON 下载),
所以对于 APP 开发和游戏开发这就存在里比较大的差异,
导致目前我们做很多游戏类应用玩法我们都是采用后者或者采用让产品去编辑 Json|XML 的方式,
更复杂的情况甚至去代码中编写配置表.
这里有 客户端代码库 做CSV据转JSON样例
具体表格格式如下:
| ##这是一个测试 | |||
|---|---|---|---|
| ID | 名字 | 描述 | 速度 |
| int | string | string | float |
| 1 | 谢大脚 | 我是谢大脚 | 3.3 |
| 2 | 赵四 | 我不是找死 | 3.4 |
具体每一行数据的作用:
- 第一行: 策划的关注的表注视信息, 采用 ## 开头标识格式表( 实际上我感觉这行可有可无 )
- 第二行: 需要表达的字段属性名, 可以是中文但最好是采用英语防止某些环境字符集导致的问题
- 第三行: 指定描述第二行对应属性的数据类型, 需要简单向策划或者产品做取值讲解让他们配置
实际上可以第一行就是字段中文含义, 第二行就是字段在代码的 key 取值, 注意策划也是必须要看懂的字段意义
优化之后我常规是这样处理:
| 标识 | 名字 | 描述 | 速度 |
|---|---|---|---|
| key | name | desc | speed |
| int | string | string | float |
| 1 | 谢大脚 | 我是谢大脚 | 3.3 |
| 2 | 赵四 | 我不是找死 | 3.4 |
这里采用 Python 脚本处理 ( csv2json.py ):
# !/usr/bin/python
# -*- coding: UTF-8 -*-
# ===============================================
# Example:
# csv2json.py -i <input_dir> -o <output_dir> -e <encode:(default utf-8)> -d <delimiter:(default ,)> -f <format:(default @)>
# CSV File:
# 策划可视文件名@代码声明类名.csv --> 物品信息@Item.csv
# ===============================================
import pathlib
import sys
import getopt
import json
import csv
# 帮助信息
def print_help(status = 0):
print("Example:\r\n\tcsv2json.py -i <input_dir> -o <output_dir> -e <encode:(default utf-8)> -d <delimiter:(default ,)> -f <format:(default @)>")
sys.exit(status)
# 查询目录符合条件的csv文件
def search_csv_file(path,format):
return [f for f in pathlib.Path(path).iterdir() if f.is_file() and f.glob(".csv") and f.glob(format)]
# 入口方法
def main(argv):
input_dir = ''
output_dir = ''
encoding = 'utf-8'
delimiter = ','
format = "@"
try:
opts, args = getopt.getopt(argv, "hi:o:e:d:f:", ["input_dir=", "output_dir=", "encode=", "delimiter=","format="])
except getopt.GetoptError:
print_help()
for opt, arg in opts:
if opt == '-h':
print_help()
elif opt in ("-i", "--input_dir"):
input_dir = arg
elif opt in ("-o", "--output_dir"):
output_dir = arg
elif opt in ("-e", "--encode"):
encoding = arg
elif opt in ("-d", "--delimiter"):
delimiter = arg
elif opt in ("-f", "--format"):
format = arg
if len(input_dir) <= 0 or len(output_dir) <= 0:
print("错误: 找不到输入|输出目录信息")
print_help()
print("输入目录: ", input_dir)
print("输出目录: ", output_dir)
files = search_csv_file(input_dir,format)
if len(files) <= 0:
print("找不到策划文件")
print_help()
# 遍历文件
csv_list = []
for file in files:
pos = file.name.find(format)
if pos != -1:
name = file.name[pos + 1:]
name = name.replace(".csv", "")
if len(name) > 0:
name = name + ".json"
print("加载策划文件: ",file, "----->", name)
csv_list.append({
"file": file,
"name": name,
})
# 遍历数据
for table in csv_list:
table_name = table["file"]
table_file = table["name"]
with open(table_name, mode="r", encoding=encoding) as file:
reader = csv.reader(file, delimiter=delimiter)
# 忽略首行类型数据
_ignore = next(reader)
keys = next(reader)
types = next(reader)
if len(keys) != len(types) and len(types) <= 0:
break
# 打印目前的csv标识和类型
count = len(keys)
print("属性名称: ",keys)
print("属性类型: ",types)
# 这里必须要认准 KEY 标识设计成 KEY-VALUE 方式
lines = {}
for row in reader:
if len(row) < count:
break
line = {}
keyboard = ""
for i in range(count):
row_type = types[i].lower()
row_key = keys[i].lower()
row_value = row[i]
if row_type == "int":
try:
row_value = int(row_value)
except ValueError:
row_value = None
elif row_type == "float":
try:
row_value = float(row_value)
except ValueError:
row_value = None
elif row_type == "string":
row_value = str(row_value)
elif row_type == "bool":
row_value = bool(row_value)
elif row_type == "array":
row_value = json.loads(row_value)
if not isinstance(row_value,list):
row_value = None
elif row_type == "object":
row_value = json.loads(row_value)
if not isinstance(row_value,dict):
row_value = None
else:
row_value = None
if row_key == "key":
keyboard = str(row_value)
line[row_key] = row_value
if len(keyboard) > 0:
lines[keyboard] = line
# 获取到数据写入JSON
if len(lines) >0:
f = pathlib.Path(output_dir)
f = f.joinpath(table_file)
print("数据文件: ",f)
print("数据合集: ",lines)
with f.open(mode="w+", encoding="utf-8") as fd:
json.dump(lines, fd, ensure_ascii=False)
# 入口调用
if __name__ == "__main__":
main(sys.argv[1:])
这里随便设置测试文件( 角色@Role.csv ), 注意文件格式名分隔符可以自定义, 但是这里采用 @ 区分策划和程序所需的文件:
| 标识 | 名字 | 描述 | 速度 | 奖励 | 推送信息 | 是否启用 |
|---|---|---|---|---|---|---|
| key | name | desc | speed | award | message | allow |
| int | string | string | float | array | object | bool |
| 1 | 谢大脚 | 我是谢大脚 | 3.3 | [2,3,4,6] | { “title”:“奖励信息”,“item”:{“2”:2,“3”:1} } | TRUE |
| 2 | 赵四 | 我不是找死 | 3.4 | [1,6,8] | { “title”:“奖励信息”,“item”:{“2”:2,“3”:1} } | FALSE |
保存到本地测试下写入即可:
# 如果 csv 是 utf8 格式直接调用即可
py .\csv2json.py -i .\csv -o .\json
# 如果 csv 是 gbk 中文格式需要追加字符集
py .\csv2json.py -i .\csv -o .\json -e gbk
执行之后就能看到具体 Role.json 格式文件:
{
"1": {
"key": 1,
"name": "谢大脚",
"desc": "我是谢大脚",
"speed": 3.3,
"award": [2,3,4,6],
"message": {
"title": "奖励信息",
"item": {
"2": 2,
"3": 1
}
},
"allow": true
},
"2": {
"key": 2,
"name": "赵四",
"desc": "我不是找死",
"speed": 3.4,
"award": [1,6,8],
"message": {
"title": "奖励信息",
"item": {
"2": 2,
"3": 1
}
},
"allow": true
}
}
这里的 key 就是对应索引 Json 数据合集, 后续就能只用通过标识直接采用数据对象.