Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have the following code which takes in a string and converts it into an object. The problem is that the string includes multiple keys that are duplicates and when turned into an object, it only recognizes the last one.

Here is my working demo http://jsfiddle.net/Qt92d/

Here is my code:

    var str = 'View\n{\n    Name: View1;\n    Image\n    {\n        BackgroundImage: Image.gif;\n        Position: 0, 0;\n        Width: 320;\n        Height: 480;\n    }\n\n    Button\n    {\n        BackgroundImage: Button.gif;\n        Transition: View2;\n        Position: 49, 80;\n        Width: 216;\n        Height: 71;\n    }\n\n    Button\n    {\n        BackgroundImage: Button2.gif;\n        Position: 65, 217;\n        Width: 188;\n        Height: 134;\n    }\n\n    Label\n    {\n        Position: 106, 91;\n        Width: 96;\n        Height: 34;\n        Text: "Button";\n        FontSize: 32;\n        Color: 0.12549, 0.298039, 0.364706, 1;\n    }\n    Scroll\n    {\n        Position: 106, 91;\n        Width: 96;\n        Height: 34;\n        Button{\n            BackgroundImage: Button2.gif;\n            Position: 65, 217;\n            Width: 188;\n            Height: 134;\n        }\n        Button{\n            BackgroundImage: Button2.gif;\n            Position: 65, 217;\n            Width: 188;\n     \n      Height: 134;\n        }\n\n    }\n\n}';

str = str.replace(/(\w+)\s*\{/g, "$1:{"); // add in colon after each named object
str = str.replace(/\}(\s*\w)/g, "},$1"); // add comma before each new named object
str = str.replace(/;/g, ","); // swap out semicolons with commas
str = str.replace(/,(\s+\})/g, "$1"); // get rid of trailing commas
str = str.replace(/([\d\.]+(, [\d\.]+)+)/g, "[$1]"); // create number arrays
str = str.replace(/"/g, ""); // get rid of all double quotes
str = str.replace(/:\s+([^\[\d\{][^,]+)/g, ':"$1"');  // create strings

$("pre").html(str);

var obj;
eval("obj={" + str + "};");

Here is the Output of the code above. Notice that there are multiple 'Buttons'. Thats where the problems start.

    View:{
    Name:"View1",
    Image:{
        BackgroundImage:"Image.gif",
        Position: [0, 0],
        Width: 320,
        Height: 480
    },

    Button:{
        BackgroundImage:"Button.gif",
        Transition:"View2",
        Position: [49, 80],
        Width: 216,
        Height: 71
    },

    Button:{
        BackgroundImage:"Button2.gif",
        Position: [65, 217],
        Width: 188,
        Height: 134
    },

    Label:{
        Position: [106, 91],
        Width: 96,
        Height: 34,
        Text:"Button",
        FontSize: 32,
        Color: [0.12549, 0.298039, 0.364706, 1]
    },
    Scroll:{
        Position: [106, 91],
        Width: 96,
        Height: 34,
        Button:{
            BackgroundImage:"Button2.gif",
            Position: [65, 217],
            Width: 188,
            Height: 134
        },
        Button:{
            BackgroundImage:"Button2.gif",
            Position: [65, 217],
            Width: 188,

      Height: 134
        }

    }

}

Im trying to figure out how to add a auto incremented number to the end of every Key i.e. View, Name,Button, Image, etc

share|improve this question
    
see here: stackoverflow.com/questions/1742798/… –  TheZuck Dec 28 '12 at 6:53
    
They use 'code''url1'.replace(/\d+$/, function(n){ return ++n });'code' which is similar to what mine is using. I altered to 'code'str = str.replace(/\d+$/, function(n){ return ++n });'code' but it did not work. Do you know what im doing wrong? Also, mine will never start with a number. I have to append a number starting with 1. –  Rob Dec 28 '12 at 7:05
    
You do definitely not want to add incremental numbers to the keys of your objects. Can you explain why you are trying to do this? –  Tomalak Dec 28 '12 at 7:10
    
The problem I have to solve is making all 'keys' of the object unique. I must keep the same format that I have posted. Currently it is dropping all duplicates except one i.e. 'Button' in my code. Appending a number to it seemed like the best option, I am definitely open to a better solution as long as the structure of the object is not changed. –  Rob Dec 28 '12 at 7:21
    
Maybe I misunderstand it, but wouldn't your problem be solved if you'd put all your objects into an array - instead of changing keys? –  Tomalak Dec 28 '12 at 7:48

1 Answer 1

up vote 1 down vote accepted

You should be using a JSON library for your object parsing. That will simplify things greatly.

As far as structuring your data, the "Button", "Label", "Scroll" type objects should be stored in an array, and the key should be in a field. I'd recommend type. For instance, you could easily represent your data in JSON as:

{                                                               
    View:{
        Name:"View1",
        Objects: [
        {
            Type: "Image",
            BackgroundImage:"Image.gif",
            Position: [0, 0],
            Width: 320,
            Height: 480
        },

        {
            Type: "Button",
            BackgroundImage:"Button.gif",
            Transition:"View2",
            Position: [49, 80],
            Width: 216,
            Height: 71
        },

        {
            Type: "Button",
            BackgroundImage:"Button2.gif",
            Position: [65, 217],
            Width: 188,
            Height: 134
        },
        {
            Type: "Label",
            Position: [106, 91],
            Width: 96,
            Height: 34,
            Text:"Button",
            FontSize: 32,
            Color: [0.12549, 0.298039, 0.364706, 1]
        },
        {
            Type: "Scroll",
            Position: [106, 91],
            Width: 96,
            Height: 34,
            Objects: [
                {
                    Type: "Button",
                    BackgroundImage:"Button2.gif",
                    Position: [65, 217],
                    Width: 188,
                    Height: 134
                },
                {
                    Type: "Button",
                    BackgroundImage:"Button2.gif",
                    Position: [65, 217],
                    Width: 188,

                    Height: 134
                }
            ]
        }
    }
}

Notice that this method supports multiple button objects.


EDIT

Given the requirements, I found this to be effective. Before any of the string replaces, add var i = 0; and add this after your final regex:

str = str.replace(/([^:]+):{/g, function(m, p1) { return p1 + "_" + (++i).toString() + ":{"; });

* This will give you your desired result at the cost of your soul *

It would not be difficult to write a simple parser/encoder for your format. A container object would look like:

{type: "view", "properties":{"name":"View1"}, "objects":[{"type":"Image","properties":{...}, "objects":[...]}, ...]}

And the logic is relatively simple. Objects are started by "[A-Za-z]+{" and closed by "}(,?)". Properties are started by "[A-Za-z]:" and are always closed by "}". Following those rules it shouldn't be hard to iterate over the characters in the string, appending each to a buffer until the buffer matches one or the other of the rules.

share|improve this answer
    
Yes, we have reviewed that, but it is not an option for us. The string that was passed in was never meant to be a json or any object for that matter. It is an instruction script for a program we have. I have to edit the value in it using a form. I have everything working except for dealing with duplicate items. The other problem is that when we are done editing the object, I have to reverse it back into the original string format and pass it back. I know its not ideal, but.... –  Rob Dec 28 '12 at 7:09
1  
Edited with a revised answer. It does more or less what you want. Either way, I highly advise against the path you're going down. Despite its appearances, your input string is actually a well formatted serialization. As I discuss in my edit, it should be easy to write a simple parser/encoder. –  Soup d'Campbells Dec 28 '12 at 7:49
    
Thank you. I added an edit to your post. I made the changes, but it threw an error. I am not sure if I did it correctly. I will look into your recommended approach, it will take a lot of reworking other code too. We will probably just add the numbers, make our change and then strip them back out when were done. This program only controls the object during edits and then it goes back to where it came from... Hope that makes sense –  Rob Dec 28 '12 at 7:55
    
The edit i guess is not showing up. here is what i edited: i=0; str = str.replace(/(\w+)\s*\{/g, "$1:{"); // add in colon after each named object <I removed some because of space in the comment> str = str.replace(/([\d\.]+(, [\d\.]+)+)/g, "[$1]"); // create number arrays str = str.replace(/"/g, ""); // get rid of all double quotes //str = str.replace(/:\s+([^\[\d\{][^,]+)/g, ':"$1"'); // create strings str = str.replace(/:\s+([^\[\d\{][^,]+)/g, function(m,p1) { return "_" + (++i.toString()) + ":" + p1; }); // create strings –  Rob Dec 28 '12 at 8:06
    
Check it again (including the instructions), and make sure you defined i. I had to edit twice after double checking what I was doing (sorry, it's 3AM here). The parser will probably save you headaches in the long run, and probably wouldn't take as much time to rework everything else as you think, but I understand the imperative to GSD. –  Soup d'Campbells Dec 28 '12 at 8:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.