csvManager.ts 18 KB

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