HuaweiDemo/assets/script/framework/csvManager.ts
2023-11-07 09:17:57 +08:00

629 lines
18 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { _decorator } from "cc";
const { ccclass, property } = _decorator;
var CELL_DELIMITERS = [",", ";", "\t", "|", "^"];
var LINE_DELIMITERS = ["\r\n", "\r", "\n"];
var getterCast = function(value: any, index: any, cast: any, d: any) {
if (cast instanceof Array) {
if (cast[index] === "number") {
return Number(d[index]);
} else if (cast[index] === "boolean") {
return d[index] === "true" || d[index] === "t" || d[index] === "1";
} else {
return d[index];
}
} else {
if (!isNaN(Number(value))) {
return Number(d[index]);
} else if (value == "false" || value == "true" || value == "t" || value == "f") {
return d[index] === "true" || d[index] === "t" || d[index] === "1";
} else {
return d[index];
}
}
};
var CSV = {
//
/* =========================================
* Constants ===============================
* ========================================= */
STANDARD_DECODE_OPTS: {
skip: 0,
limit: false,
header: false,
cast: false,
comment: ""
},
STANDARD_ENCODE_OPTS: {
delimiter: CELL_DELIMITERS[0],
newline: LINE_DELIMITERS[0],
skip: 0,
limit: false,
header: false
},
quoteMark: '"',
doubleQuoteMark: '""',
quoteRegex: /"/g,
/* =========================================
* Utility Functions =======================
* ========================================= */
assign: function () {
var args = Array.prototype.slice.call(arguments);
var base = args[0];
var rest = args.slice(1);
for (var i = 0, len = rest.length; i < len; i++) {
for (var attr in rest[i]) {
base[attr] = rest[i][attr];
}
}
return base;
},
map: function (collection: any, fn: Function) {
var results = [];
for (var i = 0, len = collection.length; i < len; i++) {
results[i] = fn(collection[i], i);
}
return results;
},
getType: function (obj: any) {
return Object.prototype.toString.call(obj).slice(8, -1);
},
getLimit: function (limit: any, len: any) {
return limit === false ? len : limit;
},
buildObjectConstructor: function(fields: any, sample: any, cast: any) {
return function(d: any) {
var object: any = new Object();
var setter = function(attr: any, value: any) {
return object[attr] = value;
};
if (cast) {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, cast, d));
});
} else {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, null, d));
});
}
// body.push("return object;");
// body.join(";\n");
return object;
};
},
buildArrayConstructor: function(fields: any, sample: any, cast: any) {
return function(d: any) {
var row = new Array(sample.length);
var setter = function(idx: any, value: any) {
return row[idx] = value;
};
if (cast) {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, cast, d));
});
} else {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, null, d));
});
}
return row;
};
},
frequency: function (coll: any, needle: any, limit: any) {
if (limit === void 0) limit = false;
var count = 0;
var lastIndex = 0;
var maxIndex = this.getLimit(limit, coll.length);
while (lastIndex < maxIndex) {
lastIndex = coll.indexOf(needle, lastIndex);
if (lastIndex === -1) break;
lastIndex += 1;
count++;
}
return count;
},
mostFrequent: function (coll: any, needles: any, limit: any) {
var max = 0;
var detected;
for (var cur = needles.length - 1; cur >= 0; cur--) {
if (this.frequency(coll, needles[cur], limit) > max) {
detected = needles[cur];
}
}
return detected || needles[0];
},
unsafeParse: function (text: any, opts: any, fn: any) {
var lines = text.split(opts.newline);
if (opts.skip > 0) {
lines.splice(opts.skip);
}
var fields;
var constructor;
function cells(lines: any) {
var line = lines.shift();
if (line.indexOf('"') >= 0) {// 含引号
// 找到这行完整的数据, 找到对称的双引号
var lastIndex = 0;
var findIndex = 0;
var count = 0;
while (lines.length > 0) {
lastIndex = line.indexOf('"', findIndex);
if (lastIndex === -1 && count % 2 === 0) break;
if (lastIndex !== -1) {
findIndex = lastIndex + 1;
count++;
} else {
line = line + opts.newline + lines.shift();
}
}
var list = [];
var item;
var quoteCount = 0;
var start = 0;
var end = 0;
var length = line.length;
for (var key in line) {
if (!line.hasOwnProperty(key)) {
continue;
}
let numKey = parseInt(key);
var value = line[key];
if (numKey === 0 && value === '"') {
quoteCount++;
start = 1;
}
if (value === '"') {
quoteCount++;
if (line[numKey - 1] === opts.delimiter && start === numKey) {
start++;
}
}
if (value === '"' && quoteCount % 2 === 0) {
if (line[numKey + 1] === opts.delimiter || numKey + 1 === length) {
end = numKey;
item = line.substring(start, end);
list.push(item);
start = end + 2;
end = start;
}
}
if (value === opts.delimiter && quoteCount % 2 === 0) {
end = numKey;
if (end > start) {
item = line.substring(start, end);
list.push(item);
start = end + 1;
end = start;
} else if (end === start) {
list.push("");
start = end + 1;
end = start;
}
}
}
end = length;
if (end >= start) {
item = line.substring(start, end);
list.push(item);
}
return list;
} else {
return line.split(opts.delimiter);
}
}
if (opts.header) {
if (opts.header === true) {
opts.comment = cells(lines); // 第一行是注释
opts.cast = cells(lines); // 第二行是数据类型
fields = cells(lines);
} else if (this.getType(opts.header) === "Array") {
fields = opts.header;
}
constructor = this.buildObjectConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
} else {
constructor = this.buildArrayConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
}
while (lines.length > 0) {
var row = cells(lines);
if (row.length > 1) {
fn(constructor(row), fields[0]);
}
}
return true;
},
safeParse: function (text: any, opts: any, fn: Function) {
var delimiter = opts.delimiter;
var newline = opts.newline;
var lines = text.split(newline);
if (opts.skip > 0) {
lines.splice(opts.skip);
}
return true;
},
encodeCells: function (line: any, delimiter: any, newline: any) {
var row = line.slice(0);
for (var i = 0, len = row.length; i < len; i++) {
if (row[i].indexOf(this.quoteMark) !== -1) {
row[i] = row[i].replace(this.quoteRegex, this.doubleQuoteMark);
}
if (row[i].indexOf(delimiter) !== -1 || row[i].indexOf(newline) !== -1) {
row[i] = this.quoteMark + row[i] + this.quoteMark;
}
}
return row.join(delimiter);
},
encodeArrays: function(coll: any, opts: any, fn: Function) {
var delimiter = opts.delimiter;
var newline = opts.newline;
if (opts.header && this.getType(opts.header) === "Array") {
fn(this.encodeCells(opts.header, delimiter, newline));
}
for (var cur = 0, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
fn(this.encodeCells(coll[cur], delimiter, newline));
}
return true;
},
encodeObjects: function (coll: any, opts: any, fn:Function) {
var delimiter = opts.delimiter;
var newline = opts.newline;
var header;
var row;
header = [];
row = [];
for (var key in coll[0]) {
header.push(key);
row.push(coll[0][key]);
}
if (opts.header === true) {
fn(this.encodeCells(header, delimiter, newline));
} else if (this.getType(opts.header) === "Array") {
fn(this.encodeCells(opts.header, delimiter, newline));
}
//@ts-ignore
fn(this.encodeCells(row, delimiter));
for (var cur = 1, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
row = [];
for (var key$1 = 0, len = header.length; key$1 < len; key$1++) {
row.push(coll[cur][header[key$1]]);
}
fn(this.encodeCells(row, delimiter, newline));
}
return true;
},
parse: function (text: any, opts: any, fn: Function) {
var rows: any;
if (this.getType(opts) === "Function") {
fn = opts;
opts = {};
} else if (this.getType(fn) !== "Function") {
rows = [];
fn = rows.push.bind(rows);
} else {
rows = [];
}
//@ts-ignore
opts = this.assign({}, this.STANDARD_DECODE_OPTS, opts);
//@ts-ignore
this.opts = opts;
if (!opts.delimiter || !opts.newline) {
var limit = Math.min(48, Math.floor(text.length / 20), text.length);
opts.delimiter = opts.delimiter || this.mostFrequent(text, CELL_DELIMITERS, limit);
opts.newline = opts.newline || this.mostFrequent(text, LINE_DELIMITERS, limit);
}
// modify by jl 由表自行控制不要含有双引号.提高解析效率
return this.unsafeParse(text, opts, fn) &&
(rows.length > 0 ? rows : true);
},
encode: function (coll: any, opts: any, fn: Function) {
var lines: any;
if (this.getType(opts) === "Function") {
fn = opts;
opts = {};
} else if (this.getType(fn) !== "Function") {
lines = [];
fn = lines.push.bind(lines);
}
//@ts-ignore
opts = this.assign({}, this.STANDARD_ENCODE_OPTS, opts);
if (opts.skip > 0) {
coll = coll.slice(opts.skip);
}
return (this.getType(coll[0]) === "Array" ? this.encodeArrays : this.encodeObjects)(coll, opts, fn) &&
(lines.length > 0 ? lines.join(opts.newline) : true);
}
};
@ccclass("CSVManager")
export class CSVManager {
/* class member could be defined like this */
static _instance: CSVManager;
static get instance () {
if (this._instance) {
return this._instance;
}
this._instance = new CSVManager();
return this._instance;
}
private _csvTables:any = {};
private _csvTableForArr:any = {};
private _tableCast:any = {};
private _tableComment:any = {};
addTable (tableName:string, tableContent:string, force?:boolean) {
if (this._csvTables[tableName] && !force) {
return;
}
let tableData: any = {};
let tableArr: any[] = [];
let opts = { header: true };
CSV.parse(tableContent, opts, function (row: any, keyName: string) {
tableData[row[keyName]] = row;
tableArr.push(row);
});
this._tableCast[tableName] = (CSV as any).opts.cast;
this._tableComment[tableName] = (CSV as any).opts.comment;
this._csvTables[tableName] = tableData;
this._csvTableForArr[tableName] = tableArr;
//this.csvTables[tableName].initFromText(tableContent);
}
/**
* 根据表名获取表的所有内容
* @param {string} tableName 表名
* @returns {object} 表内容
*/
getTableArr (tableName:string) {
return this._csvTableForArr[tableName];
}
/**
* 根据表名获取表的所有内容
* @param {string} tableName 表名
* @returns {object} 表内容
*/
getTable (tableName:string) {
return this._csvTables[tableName];
}
/**
* 查询一条表内容
* @param {string} tableName 表名
* @param {string} key 列名
* @param {any} value 值
* @returns {Object} 一条表内容
*/
queryOne (tableName:string, key:string, value:any) {
var table = this.getTable(tableName);
if (!table) {
return null;
}
if (key) {
for (var tbItem in table) {
if (!table.hasOwnProperty(tbItem)) {
continue;
}
if (table[tbItem][key] === value) {
return table[tbItem];
}
}
} else {
return table[value];
}
}
/**
* 根据ID查询一条表内容
* @param {string}tableName 表名
* @param {string}ID
* @returns {Object} 一条表内容
*/
queryByID (tableName:string, ID:string) {
//@ts-ignore
return this.queryOne(tableName, null, ID);
}
/**
* 查询key和value对应的所有行内容
* @param {string} tableName 表名
* @param {string} key 列名
* @param {any} value 值
* @returns {Object}
*/
queryAll (tableName:string, key:string, value:any) {
var table = this.getTable(tableName);
if (!table || !key) {
return null;
}
var ret: any = {};
for (var tbItem in table) {
if (!table.hasOwnProperty(tbItem)) {
continue;
}
if (table[tbItem][key] === value) {
ret[tbItem] = table[tbItem];
}
}
return ret;
}
/**
* 选出指定表里所有 key 的值在 values 数组中的数据,返回 Objectkey 为 ID
* @param {string} tableName 表名
* @param {string} key 列名
* @param {Array}values 数值
* @returns
*/
queryIn (tableName:string, key:string, values:Array<any>) {
var table = this.getTable(tableName);
if (!table || !key) {
return null;
}
var ret: any = {};
var keys = Object.keys(table);
var length = keys.length;
for (var i = 0; i < length; i++) {
var item = table[keys[i]];
if (values.indexOf(item[key]) > -1) {
ret[keys[i]] = item;
}
}
return ret;
}
/**
* 选出符合条件的数据。condition key 为表格的keyvalue 为值的数组。返回的objectkey 为数据在表格的IDvalue为具体数据
* @param {string} tableName 表名
* @param {any} condition 筛选条件
* @returns
*/
queryByCondition (tableName:string, condition: any) {
if (condition.constructor !== Object) {
return null;
}
var table = this.getTable(tableName);
if (!table) {
return null;
}
var ret: any = {};
var tableKeys = Object.keys(table);
var tableKeysLength = tableKeys.length;
var keys = Object.keys(condition);
var keysLength = keys.length;
for (var i = 0; i < tableKeysLength; i++) {
var item = table[tableKeys[i]];
var fit = true;
for (var j = 0; j < keysLength; j++) {
var key = keys[j];
fit = fit && (condition[key] === item[key]) && !ret[tableKeys[i]];
}
if (fit) {
ret[tableKeys[i]] = item;
}
}
return ret;
}
queryOneByCondition (tableName:string, condition: any) {
if (condition.constructor !== Object) {
return null;
}
var table = this.getTable(tableName);
if (!table) {
return null;
}
var keys = Object.keys(condition);
var keysLength = keys.length;
for (let keyName in table) {
var item = table[keyName];
var fit = true;
for (var j = 0; j < keysLength; j++) {
var key = keys[j];
fit = fit && (condition[key] === item[key]);
}
if (fit) {
return item;
}
}
return null;
}
}