使用JQuery或Javascript中的split()将字符串解析为JSON或Object

时间:2012-12-27 17:29:22

标签: javascript jquery json split

我得到一个传递一个独特格式的字符串(虽然是一致的),我需要能够解析它,以便我可以修改它的一部分,然后将它重新组合在一起并作为一个传回字符串。

这是传递给我的字符串。它的内容会定期更改,但每个项目结构将保持不变。

    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;
        }

    }

}

我认为我需要一个递归函数,它将寻找每个k,v并将其放入适当的Object或JSON文件中,以便我可以修改。我得到的最远的是能够解析单个级别并将其放入k,v对象中。这是代码和它解析的字符串。

修改了字符串以使用我的代码(单级深度。我删除了View {}和Scroll {}):

var content='Image{BackgroundImage: Image.gif;Position: 0, 0;Width: 320;Height: 480;}Image{BackgroundImage: Image2.gif;Position: 0, 0;Width: 320;Height: 480;}Button{BackgroundImage: Button.gif;Position: 49, 80;Width: 216;Height: 71;}Button{BackgroundImage: Button.gif;Position: 49, 80;Width: 216;Height: 71;}Button{BackgroundImage: Button2.gif;Transition: View2;Position: 65, 217;Width: 188;Height: 134;}Button{BackgroundImage: Button3.gif;Transition: View2;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;}Label{Position: 106, 91;Width: 96;Height: 34;Text: "Button";FontSize: 32;Color: 0.12549, 0.298039, 0.364706, 1;}';

        var result = content.split('}');
        result.pop();// removing the last empty element
        var obj = {Controls:{}};

        function nextProp(key) {
            /*if(obj.Controls.hasOwnProperty(key)) {
                var num = key.match(/\d+$/);
                if (num) {
                    return nextProp(key.replace(num[0], '') + (parseInt(num[0], 10) + 1));
                } else {
                    return nextProp(key + '1');
                }
            }*/

            return key;
        }

        for (var i = 0; i < result.length; i++) {
            var key = result[i].split('{');
            var value = result[i].replace(key[0], '') + '}';
            obj.Controls[nextProp(key[0])] = value;
        }

        var initObjectList = '<div id="prePop">';
        $.each(obj.Controls, function (k, v) {
        initObjectList += '<div class="inLineObjects">' + '<div class="key">' + k + '</div><br/>' + '<div  class="value">' + v + '</div>' +'</div>';

        });
    initObjectList += '</div>';
    $('#code').append(initObjectList)

返回值:

{
    "Controls": {
        "Image": "{BackgroundImage: Image.gif;Position: 0, 0;Width: 320;Height: 480;}",
        "Image1": "{BackgroundImage: Image2.gif;Position: 0, 0;Width: 320;Height: 480;}",
        "Button": "{BackgroundImage: Button.gif;Position: 49, 80;Width: 216;Height: 71;}",
        "Button1": "{BackgroundImage: Button2.gif;Transition: View2;Position: 65, 217;Width: 188;Height: 134;}",
        "Button2": "{BackgroundImage: Button3.gif;Transition: View2;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;}",
        "Label1": "{Position: 106, 91;Width: 96;Height: 34;Text: \"Button\";FontSize: 32;Color: 0.12549, 0.298039, 0.364706, 1;}"
    }
}

我的问题是以上不允许我a)。目标任何东西都在{}因为它的全部值和b)。它没有任何类型的递归能力来处理多个级别,即查看&gt;按钮&gt; scrollview

对此的任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:1)

function generalizeFunnyformat(raw) {
    "use strict";
    return ",;:{}".indexOf(raw) > -1? raw :
        " \t\r\n".indexOf(raw) > -1? " ": "a";
}

function infer(value) {
    "use strict";
    if (/^\d/.test(value)) {
        return parseFloat(value);
    } else if (/["']/.test(value)) {
        return value.substr(1, value.length - 2);
    } else {
        return value;
    }
}

function tokenEnd(state, first, second) {
    "use strict";
    state.token += first;
    if (!state.meta) {
        if (state.cursor &&
            state.cursor.hasOwnProperty(state.token)) {
            // This may be overly confident. What if primitives are also
            // allowed at the same nesting level?
            // Here we hope that coursor will be adjusted by bracket()
            // but if it doesn't happen, then we are lost.
            if (!(state.cursor[state.token] instanceof Array)) {
                state.cursor[state.token] = [state.cursor[state.token]];
            }
            state.extra = true;
            state.cursor = state.cursor[state.token];
            state.meta = state.cursor.length;
        } else {
            state.cursor[state.token] = null;
            state.meta = state.token;
        }
    } else if (state.appending) {
        if (state.cursor[state.meta] instanceof Array) {
            state.cursor[state.meta].push(state.token);
        } else {
            state.cursor[state.meta] =
                [state.cursor[state.meta], infer(state.token)];
        }
    } else {
        state.cursor[state.meta] = infer(state.token);
    }
    state.token = "";
}

function space(state, first, second) {
    "use strict";
    // noop
}

function token(state, first, secon) {
    "use strict";
    state.token += first;
}

function bracket(state, first, secon) {
    "use strict";
    var newCursor = { };
    state.cursor[state.meta] = newCursor;
    state.parents.unshift(state.cursor);
    state.cursor = newCursor;
    state.meta = "";
}

function close(state, first, second) {
    "use strict";
    state.cursor = state.parents[0];
    state.parents.shift();
    if (state.extra) {
        state.cursor = state.parents[0];
        state.parents.shift();
    }
    state.extra = false;
    state.appending = false;
}

function comma(state, first, second) {
    "use strict";
    state.appending = true;
}

function colon(state, first, second) {
    "use strict";
    state.appending = false;
}

function semi(state, first, second) {
    "use strict";
    if (state.token) {
        tokenEnd(state, "", second);
    }
    state.meta = "";
    state.appending = false;
}

function error(state, first, second) {
    "use strict";
    throw "Invalid character sequence: " + second +
        " cannot follow " + first;
}

function llparseFunnyFormat(source) {
    "use strict";
    var iterator, len = source.length - 1,
        first, second, genFirst, genSecond, handler,
        state = { result: null, cursor: { }, appending: false,
                  token: "", meta: null, parents: [], extra: false },
        parseTable = { "  ": space,
                       " :": space,
                       " a": space,
                       " ,": space,
                       " }": space,
                       " ;": space,
                       " {": space, // space
                       "aa": token,
                       "a ": tokenEnd,
                       "a:": tokenEnd,
                       "a;": tokenEnd,
                       "a{": tokenEnd,
                       "a,": tokenEnd,
                       "a}": error, // token
                       "{ ": bracket,
                       "{a": bracket,
                       "{}": bracket,
                       "{,": error,
                       "{:": error,
                       "{;": error,
                       "{{": error, // bracket
                       "} ": close,
                       "}}": close,
                       "}a": error,
                       "};": error,
                       "},": error,
                       "}:": error,
                       "}{": error, // close
                       ",,": error,
                       ",a": comma,
                       ", ": comma,
                       ",;": error,
                       ",:": error,
                       ",}": error,
                       ",{": error, // comma
                       "; ": semi,
                       ";a": semi,
                       ";}": semi,
                       ";,": error,
                       ";:": error,
                       ";;": error,
                       ";{": error, // semicolon
                       "::": error,
                       ":a": colon,
                       ": ": colon,
                       ":,": error,
                       ":;": error,
                       ":{": error,
                       ":}": error
                     };
    state.parents[0] = state.cursor;
    state.result = state.cursor;
    for (iterator = 0; iterator < len; iterator++) {
        first = source[iterator];
        second = source[iterator + 1];
        genFirst = generalizeFunnyformat(first);
        genSecond = generalizeFunnyformat(second);
        handler = parseTable[genFirst + genSecond];
        handler(state, first, second);
    }
    return state.result;
}

var test =
"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;" +
"        }" +
"" +
"    }" +
"" +
"}";

llparseFunnyFormat(test);

以上是一个公平的LL(1)解析器,我可以从你的例子中理解。它看起来像你需要的,但它可能是粗糙的边缘。特别是您可能希望使用infer()函数来更好地推断它所包含的数据类型。

它也没有使用eval() - 你显然不想在通过RPC获得的数据中使用它。

另外,如果你查看parseTable,你会看到为这种格式设计的语法有多糟糕。它有太多无效的产品(甚至JSON更好!)。因此,向提供此数据的人提问只使用JSON是完全有道理的,因为他们所做的肯定更糟。

编辑:更新了代码以将具有相同名称的密钥聚合到数组中。

答案 1 :(得分:0)

这应该有效:

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

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

alert(obj.View.Scroll.Button.Width);

唯一的问题是您的伪JSON没有唯一的属性名称。例如,Button下有两个View个属性。虽然你可以使用另一个正则表达式,但我不确定你是如何处理修复的。但这至少应该解决你的初始对象创建问题。

如果您想查看它,请查看this JSFiddle

答案 2 :(得分:-1)

好的,这应该有效。按照确切的步骤。

  
      
  1. 删除空格和换行符。
  2.   
  3. 用分号替换分号;“”(分号,dblquote,dblquote)
  4.   
  5. 用“:”替换冒号(双引号冒号dblquote)
  6.   
  7. 将开口支架替换为:{“
  8.   
  9. 用}“
  10. 替换右括号   

你应该完成。