@blog.justoneplanet.info

日々勉強

JSONをevalを使わずにパースしよう

■前置き

JavaScriptにおけるevalとは非常に強力である反面、危険でもある(正しくパースされていないJSONなど)。またscriptの実行速度を低下させたりもする。そんな訳で以下のようなコードが世界には存在する。

■json.js

// JavaScript Document
var json_parse = (function(){
	//JSONをパースして、JavaScriptのデータ構造を生成する関数。
	//これはシンプルな再帰下降パーサである
	
	//グローバル変数を生成することを避けるため、
	//この関数は他の関数の中で定義される
	
	var at;
	var ch;
	var escapee = {
		'"' : '"',
		'\\': '\\',
		'/' : '/',
		b   : 'b',
		f   : 'f',
		n   : 'n',
		r   : 'r',
		t   : 't'
	};

	var text;
	var error = function(m){
		throw{
			name   : 'SyntaxError',
			message: m,
			at     : at,
			text   : text
		};
	};

	var next = function(c){
		if(c && c !== ch){
			error("Expected '" + c + "' instead of '" + ch + "'");
		}
		ch = text.charAt(at);
		at += 1;
		return ch;
	}

	var number = function(){
		var number, string = '';
		if(ch === '-'){
			string = '-';
			next('-');
		}
		while(ch >= '0' && ch <= '9'){
			string += ch;
			next();
		}
		if(ch === '.'){
			string += '.';
			while(next() && ch >= '0' && ch <= '9'){
				string += ch;
			}
		}
		if(ch === 'e' || ch === 'E'){
			string += ch;
			next();
			if(ch === '-' || ch === '+'){
				string += ch;
				next();
			}
			while(ch >= '0' && ch <= '9'){
				string += ch;
				next();
			}
		}
		number += string;
		if(isNaN(number)){
			error("Bad number");
		}
		else{
			return number;
		}
	};

	var string = function(){
		var hex, i, string = '';
		var uffff;
		if(ch === '"'){
			while(next()){
				if(ch === '"'){
					next();
					return string;
				}
				else if(ch === '\\'){
					next();
					if(ch === 'u'){
						uffff = 0;
						for(i=0; i<4; i+=1){
							hex = parseInt(next(), 16);
							if(!isFinite(hex)){
								break;
							}
							uffff = uffff * 16 + hex;
						}
						string += String.fromCharCode(uffff);
					}
					else if(typeof escapee[ch] === 'string'){
						string += escapee[ch];
					}
					else{
						break;
					}
				}
				else{
					string += ch;
				}
			}
		}
		error("Bad string");
	};

	var white = function(){
		while(ch && ch <= ' '){
			next();
		}
	};

	var word = function(){
		switch(ch){
			case 't':
				next('t');
				next('r');
				next('u');
				next('e');
				return true;
			case 'f':
				next('f');
				next('a');
				next('l');
				next('s');
				next('e');
				return false;
			case 'n':
				next('n');
				next('u');
				next('l');
				next('l');
				return null;
		}
		error("Unexpected '" + ch + "'");
	};

	var value;
	var array = function(){
		var array = [];
		if(ch === '['){
			next('[');
			white();
			if(ch === ']'){
				next(']');
				return array;
			}
			while(ch){
				array.push(value());
				white();
				if(ch === ']'){
					next(']');
					return array;
				}
				next(',');
				white();
			}
		}
		error("Bad array");
	};

	var object = function(){
		var key;
		var object = {};
		if(ch === '{'){
			next('{');
			white();
			if(ch === '}'){
				next('}');
				return object;
			}
			while(ch){
				key = string();
				white();
				next(':');
				object[key] = value();
				white();
				if(ch === '}'){
					next('}');
					return object;
		   		}
				next(',');
				white();
			}
		}
		error("Bad object");
	};

	var value = function(){
		white();
		switch(ch){
			case '{':
				return object();
			case '[':
				return array();
			case '"':
				return string();
			case '-':
				return number();
			default:
				return (ch >= '0' && ch <= '9')? number() : word();
		}
	};

	return function(source, reviver){
		var result;
		text = source;
		at = 0;
		ch = ' ';
		result = value();
		white();
		if(ch){
			error("Syntax error");
		}
		return typeof reviver === 'function' ?
			function walk(holder, key){
				var k;
				var v;
				var value = holder[key];
				if(value && typeof value === 'object'){
					for(k in value){
						if(Object.hasOwnProperty.call(value, k)){
							v = walk(value, k);
							if(v !== undefined){
								value[k] = v;
							}
							else{
								delete value[k];
							}
						}
					}
				}
				return reviver.call(holder, key, value);
			}({'' : result}, '') : result;
	};
})();

■あとがき

出展「Douglas Crockford著『JavaScript: The Good Parts』(オライリー・ジャパン発行,2008)」

所用の為に本屋さんに言ったのですが、あまりに奥が深いので買った本です。JavaScriptを極めたいなら是非とも読んでみる事をお勧めします。

参考

コメントはまだありません»

No comments yet.

RSS feed for comments on this post.TrackBack URL

Leave a comment