var str:String = '{numA:100, numB:100, stringA:"hi there", object:{red:155, green:155, blue: 255}, array1D:[1, 2, 3, 4, 5, "six"], array2D:[[1,0,0], [0,1,0], [0,0,"z"]], color:0xFF0000}'
var obj:Object = toObject(str);//, true); // comment the "true" in for some debug info
// acess every value in the object for testing purposes
trace(obj.numA);
trace(obj.numB);
trace(obj.stringA);
trace(obj.object.red, obj.object.green, obj.object.blue);
trace(obj.array1D +" testing access: " + obj.array1D[3]);
trace(obj.array2D + " testing access: " + obj.array2D[1] + " - " + obj.array2D[2][2]);
trace(obj.color);
/*outputs:
100
100
hi there
155 155 255
1,2,3,4,5,six testing access: 4
1,0,0,0,1,0,0,0,z testing access: 0,1,0 - z
16711680
*/
function toObject(str:String, debug:Boolean=false):Object{
var cmds:Array = new Array();
var stack:String = "";
// skip first {
str = str.replace(/^s+{|^{/, "");
var obj:Object = new Object();
for (var i:int = 0; i<str.length; i++){
var char:String = str.charAt(i);
if (char == ":"){
cmds.push(["name:", stack])
stack = "";
char = "";
}else
if (char == "," || char == "}"){
if (stack != ""){
cmds.push(["value:", stack]);
}
stack = "";
char = "";
}else
if (char == '"'){
stack = '"';
for (j = i + 1; j <str.length; j++){
char = str.charAt(j);
stack+=char;
i++;
if (char == '"'){
break;
}
}
cmds.push(["value:", stack]);
stack = "";
char = "";
}else
if (char == "{"){
cmds.push(["object:", stack]);
for (var j:int = i; j <str.length; j++){
char = str.charAt(j);
stack+=char;
i++;
if (char == "}"){
break;
}
}
cmds.push(["value:", stack]);
stack = "";
char = "";
}else
if (char == "["){
cmds.push(["array:", stack]);
stack = "";
char = "";
}else if (char == "]"){
if (stack != ""){
cmds.push(["value:", stack]);
}
stack = "";
char = "";
i++;
}
stack += char;
}
// show some debug info
if (debug){
for (i = 0; i<cmds.length; i++) trace(cmds[i]);
}
// build the object
var prop:String;
var arrayMode:Boolean = false;
var nest:int = 0;
for (i = 0; i<cmds.length; i++){
if (cmds[i][0] == "name:"){
prop = cmds[i][1].replace(/s/g, "");
arrayMode = false;
nest = 0;
}else if (cmds[i][0] == "value:"){
if (arrayMode == false){
obj[prop] = valueType(cmds[i][1]);
}else{
// populate array
if (nest == 1){
obj[prop].push(valueType(cmds[i][1]))
}else{
obj[prop][nest - 2].push(valueType(cmds[i][1]))
}
}
}else if (cmds[i][0] == "object:"){
i++;
obj[prop] = toObject(cmds[i][1], debug);
}else if (cmds[i][0] == "array:"){
arrayMode = true;
nest++;
if (nest == 1){
// create array
obj[prop] = new Array()
}else{
// nested array
obj[prop].push(new Array());
}
}
}
return obj;
}
function valueType(val:*):* {
if (isNaN(Number(val))) {
// remove leading and trailing white
// remove "" around strings
val = val.replace(/^s+|s+$/g,"").replace(/^"|"$/g,"");
// see if it's a boolean
if (val == "true"){
val = true;
}else if (val == "false"){
val = false
}
} else {
val = Number(val);
}
return val;
}
This rather large code snippet parses ActionScript style Object syntax. While this is by no means a complete parser – it was easy to write and saved me a great deal of time on a project recently….
I specifically needed support for 1D and 2D arrays as Object properties. If that weren’t the case I would have used something simple like yesterdays method. The array support won’t work with anything higher than a 2D array (for now… may fix that soon). For fun I also added nested Object support – this doesn’t have any dimensional limitation so you can nest as many objects as you want. For instance.. this works just fine:
var gameUser:Object = toObject('{name:"Mr.S", alive:true, stats:{lives:100, points:1200, data:[100,12,40,12,90], plant:{branch:{leaves:["red, "green", "blue"]}}}');
trace(gameUser.stats.plant.branch.leaves[0]);
trace(gameUser.stats.lives);
// boolean support
trace("not true is false: ", !gameUser.alive);
/*outputs:
red
100
not true is false: false
*/
You’ll also notice the added boolean support in the above example. Which was suggested by katopz in the comments of yesterdays post.
Definitely need to add a word of warning here… I wouldn’t be surprised if there were a bug or two lurking in this code. The Objects I’ve been parsing with it are all quite similar… so use at your own risk.
UPDATEs – Known Issues:
1) fixed a bug where if a String property contains a ,{}[] or : character the parser failed.