Simple and rude, go directly to the code,
will parse {"a":1,"a":2}
into {"a":[1,2]}
Attach npm link: clarinet
Original link segmentfault
var clarinet = require("clarinet");
class InvalidJSON {
result = {}
/**
* @description 进入的括号层数
*/
bracketCount = 0
/**
* @type { Array<{ type: 'array'; value: any[] } | { type: 'object'; arrayKeys: string[]; arrayKeysMap: { [key: string]: boolean; }; keys: string[]; value: { [key: string]: any } }> }
*/
queue = []
get lastQueue() {
const queue = this.queue
return queue[queue.length - 1]
}
queuePop() {
this.queue.pop()
this.bracketCount--
}
queuePush(item) {
this.queue.push(item)
this.bracketCount++
}
onopenobject(key) {
// console.log('onopenobject', key)
const value = {}
this.bracketCount === 0 && (this.result = value)
this.lastQueue && this.onvalue(value)
this.queuePush({ keys: [key], arrayKeys: [], arrayKeysMap: {}, type: 'object', value })
}
onkey(key) {
// console.log('onkey', key)
const { keys, type, arrayKeys } = this.lastQueue
if (type !== 'object') { return }
keys.includes(key) && arrayKeys.push(key)
keys.push(key)
}
onvalue(v) {
// console.log('onvalue', v)
const { type, value, keys, arrayKeysMap, arrayKeys } = this.lastQueue
if (type === 'array') {
value.push(v)
} else if (type === 'object') {
const lastKeys = keys[keys.length - 1]
if (arrayKeys.includes(lastKeys)) {
if (!arrayKeysMap[lastKeys]) {
arrayKeysMap[lastKeys] = true
value[lastKeys] = [value[lastKeys]]
}
value[lastKeys].push(v)
} else {
value[lastKeys] = v
}
}
}
oncloseobject() {
// console.log('onclosearray')
this.queuePop()
}
onopenarray() {
// console.log('onopenarray')
const value = []
this.bracketCount === 0 && (this.result = value)
this.lastQueue && this.onvalue(value)
this.queuePush({ type: 'array', value })
}
onclosearray() {
// console.log('onclosearray')
this.queuePop()
}
/**
* @param { string } json 不合法的json
*/
parse(json) {
this.bracketCount = 0
this.result = {}
this.queue = []
this.parser.write(json).close()
return this.result
}
parser
constructor() {
const parser = clarinet.parser()
const parserEvents = ['value', 'openobject', 'key', 'closeobject', 'openarray', 'closearray']
parserEvents.forEach(event => {
const eventName = `on${event}`
parser[eventName] = (...args) => this[eventName](...args)
})
this.parser = parser
}
}
const invalidJSON = new InvalidJSON()
console.log(JSON.stringify(invalidJSON.parse('{"p":7,"p": 9,"w":3,"q":[0,8],"g":77,"g":{"a":100,"d":{"z":2},"d":{"z":3}}}')))
Principle: clarinet will parse the json string and trigger a callback at each key point of the json string,
Such as starting an object, entering a key, entering a value, starting an array,
Use these callbacks to assemble the desired format
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。