0

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

Rob
  • 11,185
  • 10
  • 36
  • 54
  • see here: http://stackoverflow.com/questions/1742798/increment-a-number-in-a-string-in-with-regex – TheZuck Dec 28 '12 at 06: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 07: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 07: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 07: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 07:48

1 Answers1

1

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.

Soup d'Campbells
  • 2,333
  • 15
  • 14
  • 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 07: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 07: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 07: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 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 08: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 08:15
  • Yeah, you're missing the second edit. I told you to replace the final line initially, but that was wrong. I edited again and instead said you should add a new line: `str = str.replace(/([^:]+):{/g, function(m, p1) { return p1 + "_" + (++i).toString() + ":{"; });` – Soup d'Campbells Dec 28 '12 at 08:22
  • Sorry.. No dice. Here is a demo http://jsfiddle.net/GaX6E/1/ . If you remove the last regex it works but does not capture all keys. – Rob Dec 28 '12 at 17:02
  • Fixed it for you: http://jsfiddle.net/GaX6E/2/ This is where this approach is going to start biting you in the ass. You're trying to access the property "View", but it's really "View_1" You can make this specific only to buttons if you wish (just a simple modification of the regular expression), but I'm done helping you along with this ill-advised endeavor. If you wrote a parser from the get-go you'd be done with this by now. Hack-n-slash/duck-tape solutions are good for some things, but you need to work on identifying when it's appropriate to cut corners, because this isn't one of them. – Soup d'Campbells Dec 28 '12 at 18:01