支持 ESM 和 CJS 环境,开源地址: https://github.com/jobinben/json-bn
1
bertonzh 2022-11-05 23:05:29 +08:00 9
建议先看看别人是怎么做的:
https://github.com/sidorares/json-bigint 你这几十行靠粗糙的正则替换实现的 json bigint 支持,自己在小项目里面对付简单场景可以,就不要发到 github 和 npm 了哈。 parse('{"x": ": 12345678901234561111"}') Uncaught SyntaxError: Expected ',' or '}' after property value in JSON at position 11 at JSON.parse (<anonymous>) at e (<anonymous>:1:242) at <anonymous>:1:1 |
2
bertonzh 2022-11-05 23:21:36 +08:00
其实你这个实现完善一下应该可以处理这个问题(再往前判断一下属性名的右引号)。
但是别忘了 JSON 里面有数组: parse('[12345678901234561111]') 通过正则不可能完全识别数组中 Int 。 |
3
kid740246048 2022-11-06 02:01:02 +08:00
真要搞个正经的 json 解析库的话,还是得测试先行,github 上有很多相关的 test suite ,比如:
https://github.com/nst/JSONTestSuite https://github.com/dscape/clarinet/tree/master/test |
4
himself65 2022-11-06 03:27:31 +08:00 via iPhone 13
题主有点不要脸了吧……把别的项目 download 数还专门贴到自己项目 readme 里面
https://github.com/jobinben/json-bn/commit/e14e7951835bf97242f6e7f8dd7fcae166e83f43 |
5
wxf666 2022-11-06 04:04:48 +08:00
@bertonzh `js` 新手。感觉通过正则找到数字,并替换为 `bigint`,最后再 `eval` 或 `new Function`,也能读取含有大数字的 `json` 诶:
```javascript s = '{"x": ": 12345678901234561111", "y": [-12345678901234561111, "12345678901234561111", -123456, "\\"12345678901234561111\\""]}'; eval('(' + s.replace(/"(?:\\?.)*?"|-?\d+/g, m => !isFinite(m) || Number.isSafeInteger(+m) ? m : m + 'n') + ')'); ``` 结果: ```javascript { x: ": 12345678901234561111", y: [ -12345678901234561111n, "12345678901234561111", -123456, "\"12345678901234561111\"" ] } ``` |
6
Red998 2022-11-06 10:24:41 +08:00
字符天下第一
|
7
yulon 2022-11-06 11:22:34 +08:00
用正则永远不要在函数名里带上 parse 😅
|
8
bertonzh 2022-11-06 16:25:46 +08:00
|
9
wxf666 2022-11-06 16:52:23 +08:00
@bertonzh 回头再看看,其实应该还没处理好有浮点数的 `json`。但思路是一样的,碰到字符串、浮点数,跳过就好。
如果担心 `eval` 了危险的 `js`,我觉得可以正则匹配下,看是不是全为 `json` 的元素: `/^(?:字符串|整数|浮点|true|false|null|[[\]{},]|\s+)$/` 其实,我感觉可以: 1. 正则匹配出,并用一个数组记录下所有整数,再替换为在数组中的下标。 2. `JSON.parse()` 后,再遍历所有为整数的值,替换回来(这时候就可以决定用不用 `bigint` 了) 好处: 1. 这应该会比手动解析 `json` 快 2. 而且代码体积小(可能十来行就可以了) 3. 不用担心 `eval`、`new Function` 能不能用,危不危险的问题 |
10
wxf666 2022-11-06 16:53:55 +08:00
|
11
bertonzh 2022-11-06 21:55:18 +08:00
@wxf666 你这个办法可不行,JS 遍历对象 key 的顺序并不是按照字面量 key 顺序来的,所以你无法通过数组按顺序记录整数。
另外,性能也不一定快,因为你做了三步:分词 + JSON.parse + 遍历替换,而手动解析只需要一趟(分词和生成结果同时处理)。(具体我没测过) 所以要么是用你最开始的 eval 方式。不过 eval 比 JSON.parse 更慢,因为 eval 处理的是 JS 代码,语法比 JSON 复杂很多倍。 或者用楼主的实现,即先替换成一个带特殊唯一标志的字符串,然后在 JSON.parse 的第二个回调参数里面做替换,或者在 parse 之后遍历。 |
12
wxf666 2022-11-07 01:21:17 +08:00
@bertonzh 试着写出来了:
*( V 站排版原因,行首有全角空格)* ```javascript function parseJson(json) { function restore(obj) { if (typeof obj === 'number') return nums[obj]; else if (Array.isArray(obj)) obj.forEach((v, i) => obj[i] = restore(v)); else if (typeof obj === 'object' && obj !== null) Object.keys(obj).forEach(k => obj[k] = restore(obj[k])); return obj; } let nums = []; return restore(JSON.parse(json.replace(/"(?:\\?.)*?"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g, m => m[0] === '"' ? m : nums.push(/[.eE]/.test(m) || Number.isSafeInteger(+m) ? +m : BigInt(m)) - 1 ))); } ``` 拿了个本地 64.8 MB 的 `~/.conda/pkgs/cache/e5e4a514.json` 测了下速度: *( i5-8250U ,`nodejs` v16 )* - #5 楼的方法:3.3 s - 此楼方法:2.2 s = 正则替换 1.5 s + json 解析 0.4 s + 递归替换 0.3 s - `json-bigint` *(`{useNativeBigInt: true}`)*:1.7 s |
13
chenjiangui998 2022-11-07 09:38:24 +08:00
@himself65 太无耻了
|
15
bertonzh 2022-11-07 11:13:49 +08:00
@wxf666 试试这样呢?
``` function parseJson(json) { let nums = []; return JSON.parse(json.replace(/"(?:\\?.)*?"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g, m => m[0] === '"' ? m : nums.push(/[.eE]/.test(m) || Number.isSafeInteger(+m) ? +m : BigInt(m)) - 1 ), (key, val) => typeof val === 'number' ? nums[val] : val); } ``` |