简单生成json对象 和 解析json
发布于 8 年前 作者 yongningfu 5044 次浏览 来自 分享

坐在无聊便写了一个 欢迎围观

生成json

var stringify = function (argument) {
	var result = '{';
	if (argument instanceof Object) {
		
		for (let attr in argument) {
			result += '"' + attr + '":';

			if (argument[attr] instanceof Object) {
				result += stringify(argument[attr])
			} else {
				result += argument[attr];
			}

			result += ","
		}

		//去掉最后一个 逗号
		result = result.substring(0, result.length - 1)
		result += "}"
		return result
	} else {
		throw "must be an object"
	}
}

var json = stringify({attr1: 11, attr2: {attr3: 33, attr4: 44, attr5: {attr6: 66, attr7: 77, attr8:88}}})
var parseJson = JSON.parse(json)
console.log(parseJson)

json.GIF

解析json

//这个是用来做的对称符号的  比如 'aaa { {aaa{  a}}}  {aaaa}'
//找到 第一个 { 对应的 } 位置
function findSymmetricSymbol(targetString, startIndex, leftSymbol, rightSymbol) {

	if (targetString.charAt(startIndex) !== leftSymbol) {
		throw 'argument error'
	}

	var stack = [] // 这个栈是用来 寻找 左符号的  对应的 右符号 不断入栈 出栈
	for (var i = startIndex; i < targetString.length; i++) {

		if (targetString[i] === leftSymbol)
			stack.push(leftSymbol)
		else if (targetString[i] === rightSymbol) {
			stack.pop()
			if (stack.length === 0) {
				return i
			}
		}
	}	
	return -1
}

//console.log(findSymmetricSymbol("{{aaaaa{{aaaaa{{{aaa}}aa}}aa}}a}", 7, '{', '}'))

var parse = function(argument) {

	if (typeof (argument) !== "string") {
		throw "must be a string"
	}

	//去掉所有的空格
	argument = argument.replace(/\s/g, "")
	
	return function innerParse(argument) {

		//第一个括号对于的对象 每个括号生成一个对象
		var result = {}
		var tempKey = null

		//从 1 开始 0固定为 { 即 result对象
		for (var i = 1; i < argument.length; i++) {

			//取key
			if (argument[i] === '"') {
			    var keyStartIndex = i
				var keyEndIndex = argument.indexOf('"', i + 1)
				tempKey = argument.substring(keyStartIndex + 1, keyEndIndex)
				i = keyEndIndex
			}


			if (argument[i] === ':') {
				
				//取value
				if (argument[i + 1] === '[')  {
					var tempArray = []
					var rightMiddleBracket = findSymmetricSymbol(argument, i + 1, '[', ']')
					var tempArrayString = argument.substring()


				}


				if (argument[i + 1] === '{') {

					//递归 生成对象
					var leftBracket = i + 1
					var rightBracket = findSymmetricSymbol(argument, i + 1, '{', '}')
					childrenObjString = argument.substring(leftBracket, rightBracket + 1)

					result[tempKey] = innerParse(childrenObjString)
					i = rightBracket

				} else {

					var valueEndIndex = argument.indexOf(',', i)
					//防止末尾没有 , 的情况
					if (valueEndIndex != -1) {
						result[tempKey] = argument.substring(i + 1, valueEndIndex)
						i = valueEndIndex
					} else {
						//末尾 没有 逗号
						result[tempKey] = argument.substring(i + 1, argument.length - 1)
						i = argument.length
					}
				}
			}
		}

		return result
	}(argument)
}

console.log(parse('{"aa"   :{"bb":11, "ee":  {"ff":33, "gg":44}}, "cc"  : {"dd":22, "ee":  {"ff":33}}}'))

// console.log(parse(json))

json2.GIF

解析json新版本

function findSymmetricSymbol(targetString, startIndex, leftSymbol, rightSymbol) {

	if (targetString.charAt(startIndex) !== leftSymbol) {
		throw 'argument error'
	}

	var stack = [] // 这个栈是用来 寻找 左符号的  对应的 右符号 不断入栈 出栈
	for (var i = startIndex; i < targetString.length; i++) {

		if (targetString[i] === leftSymbol)
			stack.push(leftSymbol)
		else if (targetString[i] === rightSymbol) {
			stack.pop()
			if (stack.length === 0) {
				return i
			}
		}
	}	
	return -1
}


// console.log('{{aaaaa{{aaaaa{{{aaa}}aa}}aa}}a}'.length)
// console.log(findSymmetricSymbol("{{aaaaa{{aaaaa{{{aaa}}aa}}aa}}a}", 7, '{', '}'))


function parseSimpleJson(argument) {
	
	var result = {}
	argument = argument.trim()
	argument = argument.substring(1, argument.length - 1) //去掉{ }

	var allKeyValueArray = argument.split(',')
	allKeyValueArray.forEach(function (element) {
		singleKeyAndValue = element.split(':')
		result[singleKeyAndValue[0]] =singleKeyAndValue[1]
	})
	return result
}


/*
算法思想:  把复杂的json简单话

最简单的形式:  {"aa": 11, "bb": 22}

混杂形式  {"aa": 11, "bb": {"aa": 11}}

流程为  混杂形式----转变成 {"aa": 11, "bb": token} ---->token记录在map中 map[token] = '{"aa":11}'

         把 {"aa": 11, "bb": token} 利用parseSimpleJson 转成对象

         在依次遍历 这个对象里面的属性, 如果map[attr] 存在的话,就递归 map[token] 得到这个对象

*/

var parse = function(argument) {

	//去掉所有的空格
	argument = argument.replace(/\s/g, "")
	map = {} //全局的map对象
	id = 0   //map 全局id
	
	return function innerParse(argument) {

		var result = null
		var currentIndex = 1 //跨过第一个 {
		while(currentIndex < argument.length) {

			if (argument[currentIndex] === '{') {
				var right = findSymmetricSymbol(argument, currentIndex, '{', '}')
				var subStr = argument.substring(currentIndex, right + 1)
				var uuid = (id++) + ''
				map[uuid] = subStr
				argument = argument.substring(0, currentIndex) + uuid + argument.substring(right + 1)
				currentIndex += uuid.length
			} else {
				currentIndex++
			}
		}

		result = parseSimpleJson(argument)

		// console.log(map)
		for (var key in result) {

			var mapKEY = result[key]
			if (map[mapKEY] != null) {
				// console.log(map[key])
				result[key] = innerParse(map[mapKEY])
			}
		}

		return result
	}(argument)
}


var testJ = '{"aa":  11, "bb":{" aa":11, "bb":22, "cc": {"dd": 55}}, "ff":{"dd": 66}}';
console.log(parse(testJ)['"bb"'])

完整数组版

//解析成 json

var stringify = function (argument) {
	var result = '{';
	if (argument instanceof Object) {
		
		for (let attr in argument) {
			result += '"' + attr + '":';

			if (argument[attr] instanceof Object) {

				if (argument[attr] instanceof Array) {

					let tempArray = "["
					argument[attr].forEach(function(element) {

						//防止循环引用
						if (argument === element) {
							throw "Converting circular structure to JSON"
						}

						if (element instanceof Object) {
							tempArray += stringify(element)
						} else {
							tempArray += element
						}
						tempArray += ","
					})

					tempArray = tempArray.substring(0, tempArray.length - 1)
					tempArray += "]"
					result += tempArray

				} else {

					if (argument === argument[attr]) {
						throw "Converting circular structure to JSON"
					}
					result += stringify(argument[attr])
				}
			} else {
				result += argument[attr];
			}

			result += ","
		}

		//去掉最后一个 逗号
		result = result.substring(0, result.length - 1)
		result += "}"
		return result
	} else {
		throw "must be an object"
	}
}



// 生成json对象



/*
算法思想:  把复杂的json简单话

最简单的形式:  {"aa": 11, "bb": 22}

混杂形式  {"aa": 11, "bb": {"aa": 11}, "cc":[11,22,{"aa":11}, 11]} 

混杂形式有 对象 数组

流程为   混杂形式----转变成 {"aa": 11, "bb": token1, "cc": token2} 
		 --->token1, token2记录在map中 map[token1] = '{"aa":11}' map[token2] = [11,22,{"aa":11}, 11]

         把 {"aa": 11, "bb": token1, "cc":token2} 利用parseSimpleJson 转成对象

         在依次遍历 这个对象里面的属性, 如果map[attr] 存在的话,
         如果 map[token/attr]为对象形式的字符串 就直接递归 parse
         如果 map[token/attr]为数组 就预处理数组字符串,数组字符变成 [11, 22, token3, 11]的数组对象
         然后再把 token3 变成 parse(token3)即可
*/





function findSymmetricSymbol(targetString, startIndex, leftSymbol, rightSymbol) {

	if (targetString.charAt(startIndex) !== leftSymbol) {
		throw 'argument error'
	}

	var stack = [] // 这个栈是用来 寻找 左符号的  对应的 右符号 不断入栈 出栈
	for (var i = startIndex; i < targetString.length; i++) {

		if (targetString[i] === leftSymbol)
			stack.push(leftSymbol)
		else if (targetString[i] === rightSymbol) {
			stack.pop()
			if (stack.length === 0) {
				return i
			}
		}
	}	
	return -1
}


// console.log('{{aaaaa{{aaaaa{{{aaa}}aa}}aa}}a}'.length)
// console.log(findSymmetricSymbol("{{aaaaa{{aaaaa{{{aaa}}aa}}aa}}a}", 7, '{', '}'))


function parseSimpleJson(argument) {
	
	var result = {}
	argument = argument.trim()
	argument = argument.substring(1, argument.length - 1) //去掉{ }

	var allKeyValueArray = argument.split(',')
	allKeyValueArray.forEach(function (element) {
		singleKeyAndValue = element.split(':')
		result[singleKeyAndValue[0]] =singleKeyAndValue[1]
	})
	return result
}



/*
这个是对 数组进行预处理, 生成一个
带token的 数组对象
而且token 全放入 map中        引用map
idObj是为了全局的唯一id做准备 引用传入 idObj = {id: num, prefix:_*_, suffix:_*_}
*/


function preprocessJsonArray(arrayString, map, idObj) {

	var result = null
	arrayString = arrayString.substring(1, arrayString.length - 1) //去掉[ ]
	var currentIndex = 0
	while(currentIndex < arrayString.length) {
		if (arrayString[currentIndex] === '{') {
			var right = findSymmetricSymbol(arrayString, currentIndex, '{', '}')
				var subStr = arrayString.substring(currentIndex, right + 1)
				var uuid = idObj.prefix + (idObj.id++) + idObj.suffix
				map[uuid] = subStr
				arrayString = arrayString.substring(0, currentIndex) + uuid + arrayString.substring(right + 1)
				currentIndex += uuid.length
		} else {
			currentIndex++
		}
	}

	result = arrayString.split(',')
	return result
}

// preprocessJsonArray('["aa", "bb", {"aa":11}, "cc", {"dd":22}]', {}, {"id": 0, "prefix":"_*_", "suffix":"_*_"})

/**

对 json对象的预处理
argument 为 json对象字符串 {"aa":11...}
map 为全局的存储 对象
idObj 是为了生成 uuid的

*/
function preprocessJsonObject(argument, map, idObj) {

	var result = null
	var currentIndex = 1 //跨过第一个 {
	while(currentIndex < argument.length) {

		if (argument[currentIndex] === '{' || argument[currentIndex] === '[') {

			var leftSymbol = '{'
			var rightSymbol = '}'
			if (argument[currentIndex] === '[') {
				leftSymbol = '['
				rightSymbol = ']'
			} 

			var right = findSymmetricSymbol(argument, currentIndex, leftSymbol, rightSymbol)
			var subStr = argument.substring(currentIndex, right + 1)
			var uuid = idObj.prefix + (idObj.id++) + idObj.suffix
			map[uuid] = subStr
			argument = argument.substring(0, currentIndex) + uuid + argument.substring(right + 1)
			currentIndex += uuid.length
			
		} else {
			currentIndex++
		}
	}


	result = parseSimpleJson(argument)
	return result
}


// preprocessJsonObject('{"aa":11, "bb":22, "dd":{"aa":11}, tt:"cc", ff:{"dd":22}}', {}, {"id": 0, "prefix":"_*_", "suffix":"_*_"})



// 核心代码
var parse = function(argument) {

	//去掉所有的空格
	argument = argument.replace(/\s/g, "")
	map = {} //全局的map对象
	idObj = {"id": 0, "prefix":"_*_", "suffix":"_*_"}   //map 为了生成map全局id
	
	return function innerParse(argument) {

		var result = preprocessJsonObject(argument, map, idObj)

		// console.log(result)
		for (var key in result) {

			var mapKEY = result[key]

			//只能为 数组[] 或者 对象{}的情况
			if (map[mapKEY] != null) {
				
				//区别对象和数组的情况
				if (map[mapKEY].startsWith('{')) {

					result[key] = innerParse(map[mapKEY])
				} else {
				//处理数组的情况				
					tempArrayObj = preprocessJsonArray(map[mapKEY], map, idObj)
					for (var i = 0; i < tempArrayObj.length; i++) {
						if (map[tempArrayObj[i]] != null) {
							tempArrayObj[i] = innerParse(map[tempArrayObj[i]])
						}
					}
					result[key] = tempArrayObj
				}
			}
		}

		return result
	}(argument)
}


// var testJ = '{"aa":  11, "bb":{" aa":11, "bb":22, "cc": {"dd": 55}}, "gg":[{"aa":11, "bb":22}, "aa", {"cc":11}], "ff":{"dd": 66}}';
// console.log(parse(testJ))

var testObj = { "aa": 11, 
				"bb":["aa", {"aa":11}, 11, 33], 
				"cc":{"dd": 22, "ee":{"aa":11, "bb":22}},
				"dd": 11}

var jsonString = stringify(testObj)
console.log("stringify: ",jsonString)
console.log('-----------------------')
console.log('parse: ', parse(jsonString))

json3.GIF

10 回复

补充一个循环引用的实现,circular-json 更有意思

@i5ting 循环的有空在想想 ,又写了一个解析, 谢谢狼叔的回复啊

代码看起来风格有点问题, 不知道是不是编辑器的原因

@yongningfu 感觉是markdown没弄好吧,缩进多了点,整体格式在的

有几个问题:

  1. json 里面是可以有数组的
  2. 生成 json 的方法里面,argument[attr] 如果是字符串,需要加上引号
  3. 生成 json 的方法里面,万一传入的 argument 包含循环引用怎么办

@xcatliu 居然是mobi.css大神, 你的mobi.css 我很喜欢啊, 第一个问题的话,其实 暂时不做数组的, 第二个问题的话,其实我一开始是没考虑做类型转化的,第三个问题的话,我感觉你可能是想说无限递归的情况,但是能简单的举个例子么? 还有我刚刚写了一个解析json的新思路,这个思路比之前遍历递归要简单的多, 而且核心代码 不过 30行,大神能否看看。 感谢大神回复

@xcatliu 具体的算法思想我在里面有写了的

@xcatliu @i5ting @DevinXian 添加了完整的数组版

@yongningfu 感谢关注 Mobi.css 哈哈~

  1. 如果字符串不加上引号的话,是不符合 json 标准的
  2. 举例如下:
var a = {};
a.b = a;

@xcatliu 测了一下标准库,发现它对于循环引用的问题是直接抛出异常,所以我也自己修改为抛出异常了。 字符串问题后面再抽空解决一下

回到顶部