csvManager.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. import { _decorator } from "cc";
  2. const { ccclass, property } = _decorator;
  3. var CELL_DELIMITERS = [",", ";", "\t", "|", "^"];
  4. var LINE_DELIMITERS = ["\r\n", "\r", "\n"];
  5. var getter = function (index: any) {
  6. return ("d[" + index + "]");
  7. };
  8. var getterCast = function(value: any, index: any, cast: any, d: any) {
  9. if (cast instanceof Array) {
  10. if (cast[index] === "number") {
  11. return Number(d[index]);
  12. } else if (cast[index] === "boolean") {
  13. return d[index] === "true" || d[index] === "t" || d[index] === "1";
  14. } else {
  15. return d[index];
  16. }
  17. } else {
  18. if (!isNaN(Number(value))) {
  19. return Number(d[index]);
  20. } else if (value == "false" || value == "true" || value == "t" || value == "f") {
  21. return d[index] === "true" || d[index] === "t" || d[index] === "1";
  22. } else {
  23. return d[index];
  24. }
  25. }
  26. };
  27. var CSV = {
  28. //
  29. /* =========================================
  30. * Constants ===============================
  31. * ========================================= */
  32. STANDARD_DECODE_OPTS: {
  33. skip: 0,
  34. limit: false,
  35. header: false,
  36. cast: false,
  37. comment: ""
  38. },
  39. STANDARD_ENCODE_OPTS: {
  40. delimiter: CELL_DELIMITERS[0],
  41. newline: LINE_DELIMITERS[0],
  42. skip: 0,
  43. limit: false,
  44. header: false
  45. },
  46. quoteMark: '"',
  47. doubleQuoteMark: '""',
  48. quoteRegex: /"/g,
  49. /* =========================================
  50. * Utility Functions =======================
  51. * ========================================= */
  52. assign: function () {
  53. var args = Array.prototype.slice.call(arguments);
  54. var base = args[0];
  55. var rest = args.slice(1);
  56. for (var i = 0, len = rest.length; i < len; i++) {
  57. for (var attr in rest[i]) {
  58. base[attr] = rest[i][attr];
  59. }
  60. }
  61. return base;
  62. },
  63. map: function (collection: any, fn: Function) {
  64. var results = [];
  65. for (var i = 0, len = collection.length; i < len; i++) {
  66. results[i] = fn(collection[i], i);
  67. }
  68. return results;
  69. },
  70. getType: function (obj: any) {
  71. return Object.prototype.toString.call(obj).slice(8, -1);
  72. },
  73. getLimit: function (limit: any, len: any) {
  74. return limit === false ? len : limit;
  75. },
  76. buildObjectConstructor: function(fields: any, sample: any, cast: any) {
  77. return function(d: any) {
  78. var object: any = new Object();
  79. var setter = function(attr: any, value: any) {
  80. return object[attr] = value;
  81. };
  82. if (cast) {
  83. fields.forEach(function(attr: any, idx: number) {
  84. setter(attr, getterCast(sample[idx], idx, cast, d));
  85. });
  86. } else {
  87. fields.forEach(function(attr: any, idx: number) {
  88. setter(attr, getterCast(sample[idx], idx, null, d));
  89. });
  90. }
  91. // body.push("return object;");
  92. // body.join(";\n");
  93. return object;
  94. };
  95. },
  96. buildArrayConstructor: function(fields: any, sample: any, cast: any) {
  97. return function(d: any) {
  98. var row = new Array(sample.length);
  99. var setter = function(idx: any, value: any) {
  100. return row[idx] = value;
  101. };
  102. if (cast) {
  103. fields.forEach(function(attr: any, idx: number) {
  104. setter(attr, getterCast(sample[idx], idx, cast, d));
  105. });
  106. } else {
  107. fields.forEach(function(attr: any, idx: number) {
  108. setter(attr, getterCast(sample[idx], idx, null, d));
  109. });
  110. }
  111. return row;
  112. };
  113. },
  114. frequency: function (coll: any, needle: any, limit: any) {
  115. if (limit === void 0) limit = false;
  116. var count = 0;
  117. var lastIndex = 0;
  118. var maxIndex = this.getLimit(limit, coll.length);
  119. while (lastIndex < maxIndex) {
  120. lastIndex = coll.indexOf(needle, lastIndex);
  121. if (lastIndex === -1) break;
  122. lastIndex += 1;
  123. count++;
  124. }
  125. return count;
  126. },
  127. mostFrequent: function (coll: any, needles: any, limit: any) {
  128. var max = 0;
  129. var detected;
  130. for (var cur = needles.length - 1; cur >= 0; cur--) {
  131. if (this.frequency(coll, needles[cur], limit) > max) {
  132. detected = needles[cur];
  133. }
  134. }
  135. return detected || needles[0];
  136. },
  137. unsafeParse: function (text: any, opts: any, fn: any) {
  138. var lines = text.split(opts.newline);
  139. if (opts.skip > 0) {
  140. lines.splice(opts.skip);
  141. }
  142. var fields;
  143. var constructor;
  144. function cells(lines: any) {
  145. var line = lines.shift();
  146. if (line.indexOf('"') >= 0) {// 含引号
  147. // 找到这行完整的数据, 找到对称的双引号
  148. var lastIndex = 0;
  149. var findIndex = 0;
  150. var count = 0;
  151. while (lines.length > 0) {
  152. lastIndex = line.indexOf('"', findIndex);
  153. if (lastIndex === -1 && count % 2 === 0) break;
  154. if (lastIndex !== -1) {
  155. findIndex = lastIndex + 1;
  156. count++;
  157. } else {
  158. line = line + opts.newline + lines.shift();
  159. }
  160. }
  161. var list = [];
  162. var item;
  163. var quoteCount = 0;
  164. var start = 0;
  165. var end = 0;
  166. var length = line.length;
  167. for (var key in line) {
  168. if (!line.hasOwnProperty(key)) {
  169. continue;
  170. }
  171. let numKey = parseInt(key);
  172. var value = line[key];
  173. if (numKey === 0 && value === '"') {
  174. quoteCount++;
  175. start = 1;
  176. }
  177. if (value === '"') {
  178. quoteCount++;
  179. if (line[numKey - 1] === opts.delimiter && start === numKey) {
  180. start++;
  181. }
  182. }
  183. if (value === '"' && quoteCount % 2 === 0) {
  184. if (line[numKey + 1] === opts.delimiter || numKey + 1 === length) {
  185. end = numKey;
  186. item = line.substring(start, end);
  187. list.push(item);
  188. start = end + 2;
  189. end = start;
  190. }
  191. }
  192. if (value === opts.delimiter && quoteCount % 2 === 0) {
  193. end = numKey;
  194. if (end > start) {
  195. item = line.substring(start, end);
  196. list.push(item);
  197. start = end + 1;
  198. end = start;
  199. } else if (end === start) {
  200. list.push("");
  201. start = end + 1;
  202. end = start;
  203. }
  204. }
  205. }
  206. end = length;
  207. if (end >= start) {
  208. item = line.substring(start, end);
  209. list.push(item);
  210. }
  211. return list;
  212. } else {
  213. return line.split(opts.delimiter);
  214. }
  215. }
  216. if (opts.header) {
  217. if (opts.header === true) {
  218. opts.comment = cells(lines); // 第一行是注释
  219. opts.cast = cells(lines); // 第二行是数据类型
  220. fields = cells(lines);
  221. } else if (this.getType(opts.header) === "Array") {
  222. fields = opts.header;
  223. }
  224. constructor = this.buildObjectConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
  225. } else {
  226. constructor = this.buildArrayConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
  227. }
  228. while (lines.length > 0) {
  229. var row = cells(lines);
  230. if (row.length > 1) {
  231. fn(constructor(row), fields[0]);
  232. }
  233. }
  234. return true;
  235. },
  236. safeParse: function (text: any, opts: any, fn: Function) {
  237. var delimiter = opts.delimiter;
  238. var newline = opts.newline;
  239. var lines = text.split(newline);
  240. if (opts.skip > 0) {
  241. lines.splice(opts.skip);
  242. }
  243. return true;
  244. },
  245. encodeCells: function (line: any, delimiter: any, newline: any) {
  246. var row = line.slice(0);
  247. for (var i = 0, len = row.length; i < len; i++) {
  248. if (row[i].indexOf(this.quoteMark) !== -1) {
  249. row[i] = row[i].replace(this.quoteRegex, this.doubleQuoteMark);
  250. }
  251. if (row[i].indexOf(delimiter) !== -1 || row[i].indexOf(newline) !== -1) {
  252. row[i] = this.quoteMark + row[i] + this.quoteMark;
  253. }
  254. }
  255. return row.join(delimiter);
  256. },
  257. encodeArrays: function(coll: any, opts: any, fn: Function) {
  258. var delimiter = opts.delimiter;
  259. var newline = opts.newline;
  260. if (opts.header && this.getType(opts.header) === "Array") {
  261. fn(this.encodeCells(opts.header, delimiter, newline));
  262. }
  263. for (var cur = 0, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
  264. fn(this.encodeCells(coll[cur], delimiter, newline));
  265. }
  266. return true;
  267. },
  268. encodeObjects: function (coll: any, opts: any, fn:Function) {
  269. var delimiter = opts.delimiter;
  270. var newline = opts.newline;
  271. var header;
  272. var row;
  273. header = [];
  274. row = [];
  275. for (var key in coll[0]) {
  276. header.push(key);
  277. row.push(coll[0][key]);
  278. }
  279. if (opts.header === true) {
  280. fn(this.encodeCells(header, delimiter, newline));
  281. } else if (this.getType(opts.header) === "Array") {
  282. fn(this.encodeCells(opts.header, delimiter, newline));
  283. }
  284. //@ts-ignore
  285. fn(this.encodeCells(row, delimiter));
  286. for (var cur = 1, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
  287. row = [];
  288. for (var key$1 = 0, len = header.length; key$1 < len; key$1++) {
  289. row.push(coll[cur][header[key$1]]);
  290. }
  291. fn(this.encodeCells(row, delimiter, newline));
  292. }
  293. return true;
  294. },
  295. parse: function (text: any, opts: any, fn: Function) {
  296. var rows: any;
  297. if (this.getType(opts) === "Function") {
  298. fn = opts;
  299. opts = {};
  300. } else if (this.getType(fn) !== "Function") {
  301. rows = [];
  302. fn = rows.push.bind(rows);
  303. } else {
  304. rows = [];
  305. }
  306. //@ts-ignore
  307. opts = this.assign({}, this.STANDARD_DECODE_OPTS, opts);
  308. //@ts-ignore
  309. this.opts = opts;
  310. if (!opts.delimiter || !opts.newline) {
  311. var limit = Math.min(48, Math.floor(text.length / 20), text.length);
  312. opts.delimiter = opts.delimiter || this.mostFrequent(text, CELL_DELIMITERS, limit);
  313. opts.newline = opts.newline || this.mostFrequent(text, LINE_DELIMITERS, limit);
  314. }
  315. // modify by jl 由表自行控制不要含有双引号.提高解析效率
  316. return this.unsafeParse(text, opts, fn) &&
  317. (rows.length > 0 ? rows : true);
  318. },
  319. encode: function (coll: any, opts: any, fn: Function) {
  320. var lines: any;
  321. if (this.getType(opts) === "Function") {
  322. fn = opts;
  323. opts = {};
  324. } else if (this.getType(fn) !== "Function") {
  325. lines = [];
  326. fn = lines.push.bind(lines);
  327. }
  328. //@ts-ignore
  329. opts = this.assign({}, this.STANDARD_ENCODE_OPTS, opts);
  330. if (opts.skip > 0) {
  331. coll = coll.slice(opts.skip);
  332. }
  333. return (this.getType(coll[0]) === "Array" ? this.encodeArrays : this.encodeObjects)(coll, opts, fn) &&
  334. (lines.length > 0 ? lines.join(opts.newline) : true);
  335. }
  336. };
  337. @ccclass("CSVManager")
  338. export class CSVManager {
  339. /* class member could be defined like this */
  340. static _instance: CSVManager;
  341. static get instance () {
  342. if (this._instance) {
  343. return this._instance;
  344. }
  345. this._instance = new CSVManager();
  346. return this._instance;
  347. }
  348. private _csvTables:any = {};
  349. private _csvTableForArr:any = {};
  350. private _tableCast:any = {};
  351. private _tableComment:any = {};
  352. addTable (tableName:string, tableContent:string, force?:boolean) {
  353. if (this._csvTables[tableName] && !force) {
  354. return;
  355. }
  356. let tableData: any = {};
  357. let tableArr: any[] = [];
  358. let opts = { header: true };
  359. CSV.parse(tableContent, opts, function (row: any, keyName: string) {
  360. tableData[row[keyName]] = row;
  361. tableArr.push(row);
  362. });
  363. this._tableCast[tableName] = (CSV as any).opts.cast;
  364. this._tableComment[tableName] = (CSV as any).opts.comment;
  365. this._csvTables[tableName] = tableData;
  366. this._csvTableForArr[tableName] = tableArr;
  367. //this.csvTables[tableName].initFromText(tableContent);
  368. }
  369. /**
  370. * 根据表名获取表的所有内容
  371. * @param {string} tableName 表名
  372. * @returns {object} 表内容
  373. */
  374. getTableArr (tableName:string) {
  375. return this._csvTableForArr[tableName];
  376. }
  377. /**
  378. * 根据表名获取表的所有内容
  379. * @param {string} tableName 表名
  380. * @returns {object} 表内容
  381. */
  382. getTable (tableName:string) {
  383. return this._csvTables[tableName];
  384. }
  385. /**
  386. * 查询一条表内容
  387. * @param {string} tableName 表名
  388. * @param {string} key 列名
  389. * @param {any} value 值
  390. * @returns {Object} 一条表内容
  391. */
  392. queryOne (tableName:string, key:string, value:any) {
  393. var table = this.getTable(tableName);
  394. if (!table) {
  395. return null;
  396. }
  397. if (key) {
  398. for (var tbItem in table) {
  399. if (!table.hasOwnProperty(tbItem)) {
  400. continue;
  401. }
  402. if (table[tbItem][key] === value) {
  403. return table[tbItem];
  404. }
  405. }
  406. } else {
  407. return table[value];
  408. }
  409. }
  410. /**
  411. * 根据ID查询一条表内容
  412. * @param {string}tableName 表名
  413. * @param {string}ID
  414. * @returns {Object} 一条表内容
  415. */
  416. queryByID (tableName:string, ID:string) {
  417. //@ts-ignore
  418. return this.queryOne(tableName, null, ID);
  419. }
  420. /**
  421. * 查询key和value对应的所有行内容
  422. * @param {string} tableName 表名
  423. * @param {string} key 列名
  424. * @param {any} value 值
  425. * @returns {Object}
  426. */
  427. queryAll (tableName:string, key:string, value:any) {
  428. var table = this.getTable(tableName);
  429. if (!table || !key) {
  430. return null;
  431. }
  432. var ret: any = {};
  433. for (var tbItem in table) {
  434. if (!table.hasOwnProperty(tbItem)) {
  435. continue;
  436. }
  437. if (table[tbItem][key] === value) {
  438. ret[tbItem] = table[tbItem];
  439. }
  440. }
  441. return ret;
  442. }
  443. /**
  444. * 选出指定表里所有 key 的值在 values 数组中的数据,返回 Object,key 为 ID
  445. * @param {string} tableName 表名
  446. * @param {string} key 列名
  447. * @param {Array}values 数值
  448. * @returns
  449. */
  450. queryIn (tableName:string, key:string, values:Array<any>) {
  451. var table = this.getTable(tableName);
  452. if (!table || !key) {
  453. return null;
  454. }
  455. var ret: any = {};
  456. var keys = Object.keys(table);
  457. var length = keys.length;
  458. for (var i = 0; i < length; i++) {
  459. var item = table[keys[i]];
  460. if (values.indexOf(item[key]) > -1) {
  461. ret[keys[i]] = item;
  462. }
  463. }
  464. return ret;
  465. }
  466. /**
  467. * 选出符合条件的数据。condition key 为表格的key,value 为值的数组。返回的object,key 为数据在表格的ID,value为具体数据
  468. * @param {string} tableName 表名
  469. * @param {any} condition 筛选条件
  470. * @returns
  471. */
  472. queryByCondition (tableName:string, condition: any) {
  473. if (condition.constructor !== Object) {
  474. return null;
  475. }
  476. var table = this.getTable(tableName);
  477. if (!table) {
  478. return null;
  479. }
  480. var ret: any = {};
  481. var tableKeys = Object.keys(table);
  482. var tableKeysLength = tableKeys.length;
  483. var keys = Object.keys(condition);
  484. var keysLength = keys.length;
  485. for (var i = 0; i < tableKeysLength; i++) {
  486. var item = table[tableKeys[i]];
  487. var fit = true;
  488. for (var j = 0; j < keysLength; j++) {
  489. var key = keys[j];
  490. fit = fit && (condition[key] === item[key]) && !ret[tableKeys[i]];
  491. }
  492. if (fit) {
  493. ret[tableKeys[i]] = item;
  494. }
  495. }
  496. return ret;
  497. }
  498. queryOneByCondition (tableName:string, condition: any) {
  499. if (condition.constructor !== Object) {
  500. return null;
  501. }
  502. var table = this.getTable(tableName);
  503. if (!table) {
  504. return null;
  505. }
  506. var keys = Object.keys(condition);
  507. var keysLength = keys.length;
  508. for (let keyName in table) {
  509. var item = table[keyName];
  510. var fit = true;
  511. for (var j = 0; j < keysLength; j++) {
  512. var key = keys[j];
  513. fit = fit && (condition[key] === item[key]);
  514. }
  515. if (fit) {
  516. return item;
  517. }
  518. }
  519. return null;
  520. }
  521. }